diff --git a/CMakeLists.txt b/CMakeLists.txt
index d7f1e6b99..4e2a5c5b1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -111,10 +111,10 @@ macro_optional_find_package(QCA2)
macro_log_feature(QCA2_FOUND "QCA2" "Provides encryption and signing functions required for Grooveshark resolver" "http://delta.affinix.com/qca/" FALSE "" "")
macro_optional_find_package(LibAttica)
-macro_log_feature(LIBATTICA_FOUND "libattica" "Provides support for automatic fetching and managing of resolvers from the tomahawk website" "https://projects.kde.org/projects/kdesupport/attica" FALSE "" "")
+macro_log_feature(LIBATTICA_FOUND "libattica" "Provides support for automatic fetching and managing of resolvers from the tomahawk website" "https://projects.kde.org/projects/kdesupport/attica" TRUE "" "")
macro_optional_find_package(QuaZip)
-macro_log_feature(QuaZip_FOUND "QuaZip" "Provides support for extracting downloaded resolvers automatically." "http://quazip.sourceforge.net/" FALSE "" "")
+macro_log_feature(QuaZip_FOUND "QuaZip" "Provides support for extracting downloaded resolvers automatically." "http://quazip.sourceforge.net/" TRUE "" "")
macro_optional_find_package(Jreen)
macro_log_feature(LIBJREEN_FOUND "Jreen" "Qt XMPP Library" "https://github.com/euroelessar/jreen" FALSE "" "Jreen is needed for the Jabber SIP plugin.\n")
diff --git a/CMakeModules/NSIS.template.in b/CMakeModules/NSIS.template.in
index 15e252d20..03122c6fa 100644
--- a/CMakeModules/NSIS.template.in
+++ b/CMakeModules/NSIS.template.in
@@ -280,7 +280,7 @@ Section "Tomahawk Player" SEC_TOMAHAWK_PLAYER
File "${INSTALL_PATH}\bin\libtomahawk_portfwd.dll"
File "${INSTALL_PATH}\bin\libtomahawk_lastfm2.dll"
File "${INSTALL_PATH}\bin\libtomahawklib.dll"
- File "${INSTALL_PATH}\lib\libtomahawk_sip*.dll"
+ File "${INSTALL_PATH}\lib\libtomahawk_account_*.dll"
!endif
!ifndef INSTALL_PATH
;Main executable.
@@ -293,7 +293,7 @@ Section "Tomahawk Player" SEC_TOMAHAWK_PLAYER
File "${BUILD_PATH}\libqxtweb-standalone.dll"
File "${BUILD_PATH}\libtomahawk_portfwd.dll"
File "${BUILD_PATH}\libtomahawk_lastfm2.dll"
- File "${BUILD_PATH}\libtomahawk_sip*.dll"
+ File "${BUILD_PATH}\libtomahawk_account_*.dll"
!endif
;License & release notes.
diff --git a/data/images/lastfm-icon.png b/data/images/lastfm-icon.png
new file mode 100644
index 000000000..ff605dae4
Binary files /dev/null and b/data/images/lastfm-icon.png differ
diff --git a/resources.qrc b/resources.qrc
index bd779ef74..ad8118fc5 100644
--- a/resources.qrc
+++ b/resources.qrc
@@ -134,6 +134,7 @@
data/images/no-album-no-case.png
data/images/rdio.png
data/images/grooveshark.png
+ data/images/lastfm-icon.png
data/sql/dbmigrate-27_to_28.sql
data/images/process-stop.png
diff --git a/src/AccountDelegate.cpp b/src/AccountDelegate.cpp
new file mode 100644
index 000000000..4af815b76
--- /dev/null
+++ b/src/AccountDelegate.cpp
@@ -0,0 +1,650 @@
+/*
+ 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
+
+#include "accounts/AccountModel.h"
+#include "accounts/Account.h"
+
+#include "utils/tomahawkutils.h"
+#include "utils/logger.h"
+
+#define CHILD_ACCOUNT_HEIGHT 24
+
+#define PADDING 4
+#define PADDING_BETWEEN_STARS 2
+#define STAR_SIZE 12
+
+#ifdef Q_WS_MAC
+#define TOPLEVEL_ACCOUNT_HEIGHT 72
+#else
+#define TOPLEVEL_ACCOUNT_HEIGHT 68
+#endif
+
+#define ICONSIZE 40
+#define WRENCH_SIZE 24
+#define SMALL_WRENCH_SIZE 16
+#define STATUS_ICON_SIZE 13
+#define CHECK_LEFT_EDGE 8
+#define REMOVE_ICON_SIZE 12
+
+using namespace Tomahawk;
+using namespace Accounts;
+
+AccountDelegate::AccountDelegate( QObject* parent )
+ : QStyledItemDelegate ( parent )
+{
+
+ m_defaultCover.load( RESPATH "images/sipplugin-online.png" );
+ m_ratingStarPositive.load( RESPATH "images/starred.png" );
+ m_ratingStarNegative.load( RESPATH "images/star-unstarred.png" );
+ m_onHoverStar.load( RESPATH "images/star-hover.png" );
+ m_onlineIcon.load( RESPATH "images/sipplugin-online.png" );
+ m_offlineIcon.load( RESPATH "images/sipplugin-offline.png" );
+ m_removeIcon.load( RESPATH "images/list-remove.png" );
+
+ m_ratingStarPositive = m_ratingStarPositive.scaled( STAR_SIZE, STAR_SIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation );
+ m_ratingStarNegative = m_ratingStarNegative.scaled( STAR_SIZE, STAR_SIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation );
+ m_onlineIcon = m_onlineIcon.scaled( STATUS_ICON_SIZE, STATUS_ICON_SIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation );
+ m_offlineIcon = m_offlineIcon.scaled( STATUS_ICON_SIZE, STATUS_ICON_SIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation );
+ m_onHoverStar = m_onHoverStar.scaled( STAR_SIZE, STAR_SIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation );
+ m_removeIcon = m_removeIcon.scaled( REMOVE_ICON_SIZE, REMOVE_ICON_SIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation );
+
+ m_defaultCover = m_defaultCover.scaled( ICONSIZE, ICONSIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation );
+
+}
+
+
+QSize
+AccountDelegate::sizeHint( const QStyleOptionViewItem&, const QModelIndex& index ) const
+{
+ AccountModel::RowType rowType = static_cast< AccountModel::RowType >( index.data( AccountModel::RowTypeRole ).toInt() );
+ if ( rowType == AccountModel::TopLevelAccount || rowType == AccountModel::UniqueFactory || rowType == AccountModel::CustomAccount )
+ return QSize( 200, TOPLEVEL_ACCOUNT_HEIGHT );
+ else if ( rowType == AccountModel::TopLevelFactory )
+ {
+ // Make more space for each account we have to show.
+ AccountFactory* fac = qobject_cast< AccountFactory* >( index.data( AccountModel::AccountData ).value< QObject* >() );
+ if ( fac->isUnique() )
+ return QSize( 200, TOPLEVEL_ACCOUNT_HEIGHT );
+
+ const QList< Account* > accts = index.data( AccountModel::ChildrenOfFactoryRole ).value< QList< Tomahawk::Accounts::Account* > >();
+ const QSize s = QSize( 200, TOPLEVEL_ACCOUNT_HEIGHT + 12 * accts.size()-1 );
+
+ if ( s != m_sizeHints[ index ] )
+ const_cast< AccountDelegate* >( this )->sizeHintChanged( index ); // FU KTHBBQ
+
+ m_sizeHints[ index ] = s;
+ return s;
+ }
+
+ return QSize();
+}
+
+
+void
+AccountDelegate::paint ( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const
+{
+ QStyleOptionViewItemV4 opt = option;
+ initStyleOption( &opt, index );
+
+ // draw the background
+ const QWidget* w = opt.widget;
+ QStyle* style = w ? w->style() : QApplication::style();
+ style->drawPrimitive( QStyle::PE_PanelItemViewItem, &opt, painter, w );
+
+ painter->setRenderHint( QPainter::Antialiasing );
+
+ QFont titleFont = opt.font;
+ titleFont.setBold( true );
+ titleFont.setPointSize( titleFont.pointSize() + 2 );
+ const QFontMetrics titleMetrics( titleFont );
+
+ QFont authorFont = opt.font;
+ authorFont.setItalic( true );
+ authorFont.setPointSize( authorFont.pointSize() - 1 );
+ #ifdef Q_OS_MAC
+ authorFont.setPointSize( authorFont.pointSize() - 1 );
+ #endif
+ const QFontMetrics authorMetrics( authorFont );
+
+ QFont descFont = authorFont;
+ descFont.setItalic( false );
+ const QFontMetrics descMetrics( descFont );
+
+ QFont installFont = opt.font;
+ installFont.setPointSize( installFont.pointSize() - 1 );
+ const QFontMetrics installMetrics( descFont );
+
+ const int height = opt.rect.height();
+ const int center = height / 2 + opt.rect.top();
+
+ // Left account enable/disable checkbox
+ const AccountModel::RowType rowType = static_cast< AccountModel::RowType >( index.data( AccountModel::RowTypeRole ).toInt() );
+ int leftEdge = PADDING;
+ // draw checkbox first
+ const int checkboxYPos = ( center ) - ( WRENCH_SIZE / 2 );
+ QRect checkRect = QRect( leftEdge, checkboxYPos, WRENCH_SIZE, WRENCH_SIZE );
+ QStyleOptionViewItemV4 opt2 = opt;
+ opt2.rect = checkRect;
+ drawCheckBox( opt2, painter, opt.widget );
+ leftEdge += WRENCH_SIZE + PADDING / 2;
+
+ // Pixmap
+ QPixmap p = index.data( Qt::DecorationRole ).value< QPixmap >();
+ QRect pixmapRect( leftEdge + PADDING, center - ICONSIZE/2, ICONSIZE, ICONSIZE );
+ if ( p.isNull() ) // default image... TODO
+ p = m_defaultCover;
+ else
+ p = p.scaled( pixmapRect.size(), Qt::KeepAspectRatio, Qt::SmoothTransformation );
+
+ painter->drawPixmap( pixmapRect, p );
+
+ // Draw config wrench if there is one
+ const bool hasConfigWrench = index.data( AccountModel::HasConfig ).toBool();
+ int rightEdge = opt.rect.right();
+ m_cachedConfigRects[ index ] = QRect();
+ if ( hasConfigWrench )
+ {
+ const QRect confRect = QRect( rightEdge - 2*PADDING - WRENCH_SIZE, center - WRENCH_SIZE / 2, WRENCH_SIZE, WRENCH_SIZE );
+ QStyleOptionToolButton topt;
+ topt.rect = confRect;
+ topt.pos = confRect.topLeft();
+
+ drawConfigWrench( painter, opt, topt );
+ m_cachedConfigRects[ index ] = confRect;
+ rightEdge = confRect.left();
+
+ }
+
+ // Draw individual accounts and add account button for factories
+ m_cachedButtonRects[ index ] = QRect();
+
+ bool canDelete = index.data( AccountModel::CanDeleteRole ) .toBool();
+ if ( rowType == Tomahawk::Accounts::AccountModel::TopLevelFactory )
+ {
+ const QList< Account* > accts = index.data( AccountModel::ChildrenOfFactoryRole ).value< QList< Tomahawk::Accounts::Account* > >();
+
+ QRect btnRect;
+ const QString btnText = tr( "Add Account" );
+ const int btnWidth = installMetrics.width( btnText ) + 2*PADDING;
+
+ if ( accts.isEmpty() )
+ {
+ Q_ASSERT( !hasConfigWrench );
+
+ // Draw button in center of row
+ btnRect= QRect( opt.rect.right() - PADDING - btnWidth, center - ( installMetrics.height() + 4 ) / 2, btnWidth, installMetrics.height() + 2*PADDING );
+ rightEdge = btnRect.left();
+ }
+ else
+ {
+ painter->save();
+ painter->setFont( installFont );
+ int oldRightEdge = rightEdge;
+ rightEdge = drawAccountList( painter, opt, accts, rightEdge );
+ painter->restore();
+
+ btnRect = QRect( opt.rect.right() - PADDING - btnWidth, opt.rect.bottom() - installMetrics.height() - 3*PADDING, btnWidth, installMetrics.height() + 2*PADDING );
+#ifdef Q_WS_MAC
+ btnRect.adjust( -4, 0, 4, 0 );
+#endif
+ }
+
+ leftEdge = btnRect.left();
+ m_cachedButtonRects[ index ] = btnRect;
+
+ painter->save();
+ painter->setPen( opt.palette.color( QPalette::Active, QPalette::AlternateBase ) );
+
+ drawRoundedButton( painter, btnRect );
+
+ painter->setFont( installFont );
+ painter->drawText( btnRect, Qt::AlignCenter, btnText );
+ painter->restore();
+ }
+ else if ( rowType == AccountModel::UniqueFactory )
+ {
+ // Display as usual, except if it has an account, show the status.
+ const QList< Account* > accts = index.data( AccountModel::ChildrenOfFactoryRole ).value< QList< Tomahawk::Accounts::Account* > >();
+ if ( !accts.isEmpty() )
+ {
+ Q_ASSERT( accts.size() == 1 );
+
+ rightEdge = drawStatus( painter, QPointF( rightEdge, center - painter->fontMetrics().height()/2 ), accts.first(), true );
+ }
+
+ }
+ else if ( canDelete )
+ {
+ const QString btnText = tr( "Remove Account" );
+ const int btnWidth = installMetrics.width( btnText ) + 2*PADDING;
+ QRect btnRect;
+
+ if ( hasConfigWrench )
+ btnRect = QRect( opt.rect.right() - PADDING - btnWidth, opt.rect.bottom() - installMetrics.height() - 3*PADDING, btnWidth, installMetrics.height() + 2*PADDING );
+ else
+ btnRect = QRect( opt.rect.right() - PADDING - btnWidth, center - ( installMetrics.height() + 4 ) / 2, btnWidth, installMetrics.height() + 2*PADDING );
+
+#ifdef Q_WS_MAC
+ btnRect.adjust( -4, 2, 4, -2 );
+#endif
+ leftEdge = btnRect.left();
+ m_cachedButtonRects[ index ] = btnRect;
+
+ painter->save();
+ painter->setPen( opt.palette.color( QPalette::Active, QPalette::AlternateBase ) );
+
+ drawRoundedButton( painter, btnRect, true );
+
+ painter->setFont( installFont );
+ painter->drawText( btnRect, Qt::AlignCenter, btnText );
+ painter->restore();
+ }
+
+ // Draw the title and description
+ // title
+ QString title = index.data( Qt::DisplayRole ).toString();
+ const int rightTitleEdge = rightEdge - PADDING;
+ const int leftTitleEdge = pixmapRect.right() + PADDING;
+ painter->setFont( titleFont );
+ QRect textRect;
+ const bool canRate = index.data( AccountModel::CanRateRole ).toBool();
+ if ( canRate )
+ {
+ textRect = QRect( leftTitleEdge, opt.rect.top() + PADDING, rightTitleEdge - leftTitleEdge, painter->fontMetrics().height() );
+ }
+ else
+ {
+ textRect = QRect( leftTitleEdge, opt.rect.top() + PADDING, rightTitleEdge - leftTitleEdge, center - opt.rect.top() - PADDING );
+ }
+ painter->drawText( textRect, Qt::AlignVCenter | Qt::AlignLeft, title );
+
+ // author
+ QString author = index.data( AccountModel::AuthorRole ).toString();
+ int runningBottom = textRect.bottom();
+ if ( !author.isEmpty() && canRate )
+ {
+ painter->save();
+ painter->setFont( authorFont );
+ painter->setPen( QColor( Qt::gray ).darker( 150 ) );
+ const int authorWidth = authorMetrics.width( author );
+ const QRect authorRect( textRect.left(), textRect.bottom() + PADDING/2, authorWidth + 6, authorMetrics.height() );
+ painter->drawText( authorRect, Qt::AlignLeft | Qt::AlignVCenter, author );
+ painter->restore();
+
+ runningBottom = authorRect.bottom();
+ }
+
+ // description
+ QString desc = index.data( AccountModel::DescriptionRole ).toString();
+ const int descWidth = rightEdge - leftTitleEdge - PADDING;
+ painter->setFont( descFont );
+ const QRect descRect( leftTitleEdge, runningBottom + PADDING, descWidth, painter->fontMetrics().height() );
+ desc = painter->fontMetrics().elidedText( desc, Qt::ElideRight, descWidth );
+ painter->drawText( descRect, Qt::AlignLeft | Qt::TextWordWrap | Qt::AlignTop, desc );
+ runningBottom = descRect.bottom();
+
+ if ( index.data( AccountModel::CanRateRole ).toBool() )
+ {
+ // rating stars
+ const int rating = index.data( AccountModel::RatingRole ).toInt();
+
+// int runningEdge = opt.rect.right() - 2*PADDING - ratingWidth;
+ int runningEdge = textRect.left();
+// int starsTop = opt.rect.bottom() - 3*PADDING - m_ratingStarNegative.height();
+ int starsTop = runningBottom + PADDING;
+ for ( int i = 1; i < 6; i++ )
+ {
+ QRect r( runningEdge, starsTop, m_ratingStarPositive.width(), m_ratingStarPositive.height() );
+// QRect r( runningEdge, opt.rect.top() + PADDING, m_ratingStarPositive.width(), m_ratingStarPositive.height() );
+ if ( i == 1 )
+ m_cachedStarRects[ index ] = r;
+
+ const bool userHasRated = index.data( AccountModel::UserHasRatedRole ).toBool();
+ if ( !userHasRated && // Show on-hover animation if the user hasn't rated it yet, and is hovering over it
+ m_hoveringOver > -1 &&
+ m_hoveringItem == index )
+ {
+ if ( i <= m_hoveringOver ) // positive star
+ painter->drawPixmap( r, m_onHoverStar );
+ else
+ painter->drawPixmap( r, m_ratingStarNegative );
+ }
+ else
+ {
+ if ( i <= rating ) // positive or rated star
+ {
+ if ( userHasRated )
+ painter->drawPixmap( r, m_onHoverStar );
+ else
+ painter->drawPixmap( r, m_ratingStarPositive );
+ }
+ else
+ painter->drawPixmap( r, m_ratingStarNegative );
+ }
+ runningEdge += m_ratingStarPositive.width() + PADDING_BETWEEN_STARS;
+ }
+
+ // downloaded num times
+ QString count = tr( "%1 downloads" ).arg( index.data( AccountModel::DownloadCounterRole ).toInt() );
+ painter->setFont( descFont );
+ const int countW = painter->fontMetrics().width( count );
+ const QRect countRect( runningEdge + 50, starsTop, countW, painter->fontMetrics().height() );
+ count = painter->fontMetrics().elidedText( count, Qt::ElideRight, rightEdge - PADDING - countRect.left() );
+ painter->drawText( countRect, Qt::AlignLeft | Qt::TextWordWrap, count );
+ // runningEdge = authorRect.x();
+ }
+
+ // Title and description!
+ return;
+}
+
+
+int
+AccountDelegate::drawAccountList( QPainter* painter, QStyleOptionViewItemV4& opt, const QList< Account* > accts, int rightEdge ) const
+{
+ // list each account name, and show the online, offline icon
+ const int textHeight = painter->fontMetrics().height() + 1;
+ const int mid = opt.rect.bottom() - opt.rect.height() / 2;
+ int runningRightEdge = rightEdge;
+ int current = 0;
+
+ int leftOfAccounts = rightEdge;
+
+ if ( accts.size() % 2 == 1 )
+ {
+ // If there's an odd number, the center one is centered
+ current = mid - ((textHeight + PADDING/2) * (accts.size()/2) ) - textHeight / 2;
+ }
+ else
+ {
+ // Even number, center between the middle ones
+ current = mid - ((textHeight + PADDING/2) * (accts.size()/2) );
+ }
+
+ for ( int i = 0; i < accts.size(); i++ )
+ {
+ // draw lightbulb and text
+ runningRightEdge = drawStatus( painter, QPointF( rightEdge - PADDING, current), accts.at( i ) );
+
+ const QString label = accts.at( i )->accountFriendlyName();
+ const QPoint textTopLeft( runningRightEdge - PADDING - painter->fontMetrics().width( label ), current);
+ painter->drawText( QRect( textTopLeft, QSize( painter->fontMetrics().width( label ) + 1, textHeight ) ), label );
+
+ current += textHeight + PADDING/2;
+
+ leftOfAccounts = qMin( leftOfAccounts, textTopLeft.x() );
+ }
+
+ return leftOfAccounts;
+}
+
+
+bool
+AccountDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, 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;
+
+ const AccountModel::RowType rowType = static_cast< AccountModel::RowType >( index.data( AccountModel::RowTypeRole ).toInt() );
+ if ( rowType == AccountModel::TopLevelAccount ||
+ rowType == AccountModel::CustomAccount )
+ {
+ 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 )
+ {
+ QMouseEvent* me = static_cast< QMouseEvent* >( event );
+ if ( m_configPressed.isValid() )
+ emit update( m_configPressed );
+
+ m_configPressed = QModelIndex();
+
+ if ( checkRectForIndex( option, index ).contains( me->pos() ) )
+ {
+ // Check box for this row
+
+ // 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( Qt::CheckStateRole ).toInt() );
+ Qt::CheckState newState = curState == Qt::Checked ? Qt::Unchecked : Qt::Checked;
+ return model->setData( index, newState, AccountModel::CheckboxClickedRole );
+ }
+ else if ( m_cachedButtonRects.contains( index ) && m_cachedButtonRects[ index ].contains( me->pos() ) )
+ {
+ // Install/create/etc button for this row
+ model->setData( index, true, AccountModel::CustomButtonRole );
+ }
+ }
+
+ if ( m_cachedStarRects.contains( index ) )
+ {
+ QRect fullStars = m_cachedStarRects[ index ];
+ const int starsWidth = 5 * ( m_ratingStarPositive.width() + PADDING_BETWEEN_STARS );
+ fullStars.setWidth( starsWidth );
+
+ QMouseEvent* me = static_cast< QMouseEvent* >( event );
+
+ if ( fullStars.contains( me->pos() ) )
+ {
+ const int eachStar = starsWidth / 5;
+ const int clickOffset = me->pos().x() - fullStars.x();
+ const int whichStar = (clickOffset / eachStar) + 1;
+
+ if ( event->type() == QEvent::MouseButtonRelease )
+ {
+ model->setData( index, whichStar, AccountModel::RatingRole );
+ }
+ else if ( event->type() == QEvent::MouseMove )
+ {
+ // 0-indexed
+ m_hoveringOver = whichStar;
+ m_hoveringItem = index;
+ }
+
+ return true;
+ }
+ }
+
+ if ( m_hoveringOver > -1 )
+ {
+ emit update( m_hoveringItem );
+ m_hoveringOver = -1;
+ m_hoveringItem = QPersistentModelIndex();
+ }
+ return false;
+}
+
+
+void
+AccountDelegate::drawRoundedButton( QPainter* painter, const QRect& btnRect, bool red ) const
+{
+ QPainterPath btnPath;
+ const int radius = 3;
+ // draw top half gradient
+ const int btnCenter = btnRect.bottom() - ( btnRect.height() / 2 );
+ btnPath.moveTo( btnRect.left(), btnCenter );
+ btnPath.lineTo( btnRect.left(), btnRect.top() + radius );
+ btnPath.quadTo( QPoint( btnRect.topLeft() ), QPoint( btnRect.left() + radius, btnRect.top() ) );
+ btnPath.lineTo( btnRect.right() - radius, btnRect.top() );
+ btnPath.quadTo( QPoint( btnRect.topRight() ), QPoint( btnRect.right(), btnRect.top() + radius ) );
+ btnPath.lineTo( btnRect.right(),btnCenter );
+ btnPath.lineTo( btnRect.left(), btnCenter );
+
+ QLinearGradient g;
+ if ( !red )
+ {
+ g.setColorAt( 0, QColor(54, 127, 211) );
+ g.setColorAt( 0.5, QColor(43, 104, 182) );
+ }
+ else
+ {
+ g.setColorAt( 0, QColor(206, 63, 63) );
+ g.setColorAt( 0.5, QColor(170, 52, 52) );
+ }
+ //painter->setPen( bg.darker() );
+ painter->fillPath( btnPath, g );
+ //painter->drawPath( btnPath );
+
+ btnPath = QPainterPath();
+ btnPath.moveTo( btnRect.left(), btnCenter );
+ btnPath.lineTo( btnRect.left(), btnRect.bottom() - radius );
+ btnPath.quadTo( QPoint( btnRect.bottomLeft() ), QPoint( btnRect.left() + radius, btnRect.bottom() ) );
+ btnPath.lineTo( btnRect.right() - radius, btnRect.bottom() );
+ btnPath.quadTo( QPoint( btnRect.bottomRight() ), QPoint( btnRect.right(), btnRect.bottom() - radius ) );
+ btnPath.lineTo( btnRect.right(), btnCenter );
+ btnPath.lineTo( btnRect.left(), btnCenter );
+
+ if ( !red )
+ {
+ g.setColorAt( 0, QColor(34, 85, 159) );
+ g.setColorAt( 0.5, QColor(35, 79, 147) );
+ }
+ else
+ {
+ g.setColorAt( 0, QColor(150, 50, 50) );
+ g.setColorAt( 0.5, QColor(130, 40, 40) );
+ }
+ painter->fillPath( btnPath, g );
+}
+
+
+int
+AccountDelegate::drawStatus( QPainter* painter, const QPointF& rightTopEdge, Account* acct, bool drawText ) const
+{
+ QPixmap p;
+ QString statusText;
+ Account::ConnectionState state = acct->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 int yPos = rightTopEdge.y();
+ const QRect connectIconRect( rightTopEdge.x() - STATUS_ICON_SIZE, yPos, STATUS_ICON_SIZE, STATUS_ICON_SIZE );
+ painter->drawPixmap( connectIconRect, p );
+
+ int leftEdge = connectIconRect.x();
+ if ( drawText )
+ {
+ int width = painter->fontMetrics().width( statusText );
+ int statusTextX = connectIconRect.x() - PADDING - width;
+ painter->drawText( QRect( statusTextX, yPos, width, painter->fontMetrics().height() ), statusText );
+
+ leftEdge = statusTextX;
+ }
+
+ return leftEdge;
+}
+
+
+void
+AccountDelegate::drawCheckBox( QStyleOptionViewItemV4& opt, QPainter* p, const QWidget* w ) const
+{
+ QStyle* style = w ? w->style() : QApplication::style();
+ opt.checkState == Qt::Checked ? opt.state |= QStyle::State_On : opt.state |= QStyle::State_Off;
+ style->drawPrimitive( QStyle::PE_IndicatorViewItemCheck, &opt, p, w );
+}
+
+
+void
+AccountDelegate::drawConfigWrench ( QPainter* painter, QStyleOptionViewItemV4& opt, QStyleOptionToolButton& topt ) const
+{
+ const QWidget* w = opt.widget;
+ QStyle* style = w ? w->style() : QApplication::style();
+
+ // draw it the same size as the check belox
+ topt.font = opt.font;
+ topt.icon = QIcon( RESPATH "images/configure.png" );
+ topt.iconSize = QSize( 14, 14 );
+ 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 );
+}
+
+
+
+QRect
+AccountDelegate::checkRectForIndex( const QStyleOptionViewItem& option, const QModelIndex& idx ) const
+{
+ QStyleOptionViewItemV4 opt = option;
+ initStyleOption( &opt, idx );
+
+ // Top level item, return the corresponding rect
+ const int ypos = ( opt.rect.top() + opt.rect.height() / 2 ) - ( WRENCH_SIZE / 2 );
+ const QRect checkRect = QRect( PADDING, ypos, WRENCH_SIZE, WRENCH_SIZE );
+
+ return checkRect;
+
+}
+
+
diff --git a/src/AccountDelegate.h b/src/AccountDelegate.h
new file mode 100644
index 000000000..6787489b4
--- /dev/null
+++ b/src/AccountDelegate.h
@@ -0,0 +1,72 @@
+/*
+ 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 .
+*/
+
+
+#ifndef ACCOUNTDELEGATE_H
+#define ACCOUNTDELEGATE_H
+
+#include
+#include "accounts/AccountModel.h"
+
+namespace Tomahawk
+{
+namespace Accounts
+{
+
+class Account;
+
+class AccountDelegate : public QStyledItemDelegate
+{
+ Q_OBJECT
+public:
+ AccountDelegate( 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;
+
+protected:
+ virtual bool editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index );
+
+signals:
+ void update( const QModelIndex& idx );
+ void openConfig( Tomahawk::Accounts::Account* );
+ void openConfig( Tomahawk::Accounts::AccountFactory* );
+
+private:
+ void drawRoundedButton( QPainter* painter, const QRect& buttonRect, bool red = false ) const;
+ // Returns new left edge
+ int drawStatus( QPainter* painter, const QPointF& rightTopEdge, Account* acct, bool drawText = false ) const;
+ void drawCheckBox( QStyleOptionViewItemV4& opt, QPainter* p, const QWidget* w ) const;
+ void drawConfigWrench( QPainter* painter, QStyleOptionViewItemV4& option, QStyleOptionToolButton& topt ) const;
+ // returns new left edge
+ int drawAccountList( QPainter* painter, QStyleOptionViewItemV4& option, const QList< Account* > accounts, int rightEdge ) const;
+
+ QRect checkRectForIndex( const QStyleOptionViewItem &option, const QModelIndex &idx ) const;
+
+ QPixmap m_offlineIcon, m_onlineIcon, m_defaultCover, m_onHoverStar, m_ratingStarPositive, m_ratingStarNegative, m_removeIcon;
+ int m_hoveringOver;
+ QPersistentModelIndex m_hoveringItem, m_configPressed;
+ mutable QHash< QPersistentModelIndex, QRect > m_cachedButtonRects;
+ mutable QHash< QPersistentModelIndex, QRect > m_cachedStarRects;
+ mutable QHash< QPersistentModelIndex, QRect > m_cachedConfigRects;
+ mutable QHash< QPersistentModelIndex, QSize > m_sizeHints;
+};
+
+}
+}
+
+#endif // ACCOUNTDELEGATE_H
diff --git a/src/AccountFactoryWrapper.cpp b/src/AccountFactoryWrapper.cpp
new file mode 100644
index 000000000..f5f270b06
--- /dev/null
+++ b/src/AccountFactoryWrapper.cpp
@@ -0,0 +1,149 @@
+/* === 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( QAbstractButton* ) ) );
+
+
+ connect ( AccountManager::instance(), SIGNAL( added( Tomahawk::Accounts::Account* ) ), this, SLOT( load() ) );
+ connect ( AccountManager::instance(), SIGNAL( removed( Tomahawk::Accounts::Account* ) ), this, SLOT( load() ) );
+
+#ifdef Q_OS_MAC
+ setContentsMargins( 0, 0, 0, 0 );
+ m_ui->verticalLayout->setSpacing( 6 );
+#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 ) );
+ }
+ }
+
+ if ( m_ui->accountsList->model()->rowCount() == 0 )
+ accept();
+
+#ifndef Q_OS_MAC
+ const int padding = 7;
+#else
+ const int padding = 8;
+#endif
+ const int height = m_ui->accountsList->model()->rowCount( QModelIndex() ) * ACCOUNT_ROW_HEIGHT + padding;
+
+ 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 );
+ return;
+ }
+ else
+ reject();
+}
+
diff --git a/src/AccountFactoryWrapper.h b/src/AccountFactoryWrapper.h
new file mode 100644
index 000000000..02c8ec335
--- /dev/null
+++ b/src/AccountFactoryWrapper.h
@@ -0,0 +1,66 @@
+/* === 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* );
+ void load();
+
+private:
+ 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..b7ba54df3
--- /dev/null
+++ b/src/AccountFactoryWrapper.ui
@@ -0,0 +1,110 @@
+
+
+ AccountFactoryWrapper
+
+
+
+ 0
+ 0
+ 507
+ 150
+
+
+
+ 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/GetNewStuffDelegate.h b/src/AccountFactoryWrapperDelegate.h
similarity index 52%
rename from src/GetNewStuffDelegate.h
rename to src/AccountFactoryWrapperDelegate.h
index 570210226..699ed22f8 100644
--- a/src/GetNewStuffDelegate.h
+++ b/src/AccountFactoryWrapperDelegate.h
@@ -1,6 +1,6 @@
/* === This file is part of Tomahawk Player - ===
*
- * Copyright 2010-2011, Leo Franchi
+ * 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
@@ -16,35 +16,43 @@
* along with Tomahawk. If not, see .
*/
-#ifndef GETNEWSTUFFDELEGATE_H
-#define GETNEWSTUFFDELEGATE_H
+#ifndef ACCOUNTFACTORYWRAPPERDELEGATE_H
+#define ACCOUNTFACTORYWRAPPERDELEGATE_H
#include
+#define ACCOUNT_ROW_HEIGHT 20
-class
-GetNewStuffDelegate : public QStyledItemDelegate
+namespace Tomahawk {
+namespace Accounts {
+class Account;
+}
+}
+
+class AccountFactoryWrapperDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
- explicit GetNewStuffDelegate( QObject* parent = 0 );
+ 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& idx );
+ void update( const QModelIndex& );
-protected:
- virtual bool editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index );
+ void openConfig( Tomahawk::Accounts::Account* );
+ void removeAccount( Tomahawk::Accounts::Account* );
private:
- QPixmap m_defaultCover, m_onHoverStar, m_ratingStarPositive, m_ratingStarNegative;
+ QPixmap m_removePixmap, m_offlineIcon, m_onlineIcon;
+ QIcon m_configIcon;
+ QModelIndex m_configPressed;
- int m_widestTextWidth;
- int m_hoveringOver;
- QPersistentModelIndex m_hoveringItem;
- mutable QHash< QPair, QRect > m_cachedButtonRects;
- mutable QHash< QPair, QRect > m_cachedStarRects;
+ mutable QHash< QPersistentModelIndex, QRect > m_cachedButtonRects;
+ mutable QHash< QPersistentModelIndex, QRect > m_cachedConfigRects;
};
-#endif // GETNEWSTUFFDELEGATE_H
+#endif // ACCOUNTFACTORYWRAPPERDELEGATE_H
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index ee9d3fbe6..ee8ac9b0b 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -74,13 +74,12 @@ SET( tomahawkSourcesGui ${tomahawkSourcesGui}
audiocontrols.cpp
settingsdialog.cpp
diagnosticsdialog.cpp
- configdelegatebase.cpp
- sipconfigdelegate.cpp
- resolverconfigdelegate.cpp
+ AccountDelegate.cpp
settingslistdelegate.cpp
- resolversmodel.cpp
tomahawkwindow.cpp
LoadXSPFDialog.cpp
+ AccountFactoryWrapper.cpp
+ AccountFactoryWrapperDelegate.cpp
)
SET( tomahawkHeaders ${tomahawkHeaders}
@@ -100,13 +99,6 @@ IF(LIBLASTFM_FOUND)
)
ENDIF(LIBLASTFM_FOUND)
-IF(LIBATTICA_FOUND)
- SET( tomahawkSourcesGui ${tomahawkSourcesGui} GetNewStuffDialog.cpp GetNewStuffDelegate.cpp GetNewStuffModel.cpp )
- SET( tomahawkHeadersGui ${tomahawkHeadersGui} GetNewStuffDialog.h GetNewStuffDelegate.h GetNewStuffModel.h )
- INCLUDE_DIRECTORIES( ${LIBATTICA_INCLUDE_DIR} )
-ENDIF(LIBATTICA_FOUND)
-
-
SET( tomahawkHeadersGui ${tomahawkHeadersGui}
sourcetree/sourcesmodel.h
sourcetree/sourcesproxymodel.h
@@ -126,14 +118,13 @@ SET( tomahawkHeadersGui ${tomahawkHeadersGui}
audiocontrols.h
settingsdialog.h
diagnosticsdialog.h
- configdelegatebase.h
- resolverconfigdelegate.h
- sipconfigdelegate.h
+ AccountDelegate.h
settingslistdelegate.h
- resolversmodel.h
delegateconfigwrapper.h
tomahawkwindow.h
LoadXSPFDialog.h
+ AccountFactoryWrapper.h
+ AccountFactoryWrapperDelegate.h
)
SET( tomahawkUI ${tomahawkUI}
@@ -144,8 +135,9 @@ SET( tomahawkUI ${tomahawkUI}
audiocontrols.ui
- GetNewStuffDialog.ui
LoadXSPFDialog.ui
+
+ AccountFactoryWrapper.ui
)
INCLUDE_DIRECTORIES(
@@ -171,6 +163,7 @@ INCLUDE_DIRECTORIES(
${TAGLIB_INCLUDES}
${PHONON_INCLUDES}
${QJSON_INCLUDE_DIR}
+ ${LIBATTICA_INCLUDE_DIR}
${LIBECHONEST_INCLUDE_DIR}
${LIBECHONEST_INCLUDE_DIR}/..
)
@@ -200,7 +193,8 @@ IF(GLOOX_FOUND)
SET( tomahawkHeaders ${tomahawkHeaders} xmppbot/xmppbot.h )
SET( tomahawkSources ${tomahawkSources} xmppbot/xmppbot.cpp )
ENDIF(GLOOX_FOUND)
-ADD_SUBDIRECTORY( sip )
+
+ADD_SUBDIRECTORY( accounts )
IF(QCA2_FOUND)
INCLUDE_DIRECTORIES( ${QCA2_INCLUDE_DIR} )
diff --git a/src/GetNewStuffDelegate.cpp b/src/GetNewStuffDelegate.cpp
deleted file mode 100644
index 1e1c5d381..000000000
--- a/src/GetNewStuffDelegate.cpp
+++ /dev/null
@@ -1,323 +0,0 @@
-/* === 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 "GetNewStuffDelegate.h"
-
-#include "GetNewStuffModel.h"
-#include "utils/tomahawkutils.h"
-#include "utils/logger.h"
-
-#include
-#include
-#include
-#include "AtticaManager.h"
-
-#define PADDING 4
-#define PADDING_BETWEEN_STARS 2
-#define STAR_SIZE 12
-
-#ifdef Q_WS_MAC
-#define SIZEHINT_HEIGHT 70
-#else
-#define SIZEHINT_HEIGHT 60
-#endif
-
-GetNewStuffDelegate::GetNewStuffDelegate( QObject* parent )
- : QStyledItemDelegate ( parent )
- , m_widestTextWidth( 0 )
- , m_hoveringOver( -1 )
-{
- m_defaultCover.load( RESPATH "images/sipplugin-online.png" );
- m_ratingStarPositive.load( RESPATH "images/starred.png" );
- m_ratingStarNegative.load( RESPATH "images/star-unstarred.png" );
- m_onHoverStar.load( RESPATH "images/star-hover.png" );
-
- m_ratingStarPositive = m_ratingStarPositive.scaled( STAR_SIZE, STAR_SIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation );
- m_ratingStarNegative = m_ratingStarNegative.scaled( STAR_SIZE, STAR_SIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation );
- m_onHoverStar = m_onHoverStar.scaled( STAR_SIZE, STAR_SIZE, Qt::KeepAspectRatio, Qt::SmoothTransformation );
-
- const int w = SIZEHINT_HEIGHT - 2*PADDING;
- m_defaultCover = m_defaultCover.scaled( w, w, Qt::KeepAspectRatio, Qt::SmoothTransformation );
-
- // save the widest wifth
- QFont f( QApplication::font() );
- f.setPointSize( f.pointSize() - 1 );
- QFontMetrics fm( f );
- QStringList l = QStringList() << tr( "Installed" ) << tr( "Installing" ) << tr( "Failed" ) << tr( "Uninstalling" );
- foreach ( const QString& str, l )
- {
- if ( fm.width( str ) > m_widestTextWidth )
- m_widestTextWidth = fm.width( str );
- }
-}
-
-void
-GetNewStuffDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const
-{
- QStyleOptionViewItemV4 opt = option;
- initStyleOption( &opt, index );
-
- QApplication::style()->drawPrimitive( QStyle::PE_PanelItemViewItem, &opt, painter, opt.widget );
-
- painter->setRenderHint( QPainter::Antialiasing );
-
- QFont titleFont = opt.font;
- titleFont.setBold( true );
- titleFont.setPointSize( titleFont.pointSize() + 2 );
- QFontMetrics titleMetrics( titleFont );
-
- QFont authorFont = opt.font;
- authorFont.setItalic( true );
- authorFont.setPointSize( authorFont.pointSize() - 1 );
- QFontMetrics authorMetrics( authorFont );
-
- QFont descFont = authorFont;
- descFont.setItalic( false );
- QFontMetrics descMetrics( descFont );
-
- QFont installFont = opt.font;
- installFont.setPointSize( installFont.pointSize() - 1 );
- QFontMetrics installMetrics( descFont );
-
- const int height = opt.rect.height();
- const int center = height / 2 + opt.rect.top();
-
- // Pixmap
- QPixmap p = index.data( Qt::DecorationRole ).value< QPixmap >();
- const int pixmapWidth = height - 2*PADDING;
- QRect pixmapRect( PADDING, PADDING + opt.rect.top(), pixmapWidth, pixmapWidth );
- if ( p.isNull() ) // default image... TODO
- p = m_defaultCover;
- else
- p = p.scaled( pixmapRect.size(), Qt::KeepAspectRatio, Qt::SmoothTransformation );
-
- painter->drawPixmap( pixmapRect, p );
-
- // Go from right edge now, stars, install button, and downloaded info
-
- // install / status button
- AtticaManager::ResolverState state = static_cast< AtticaManager::ResolverState >( index.data( GetNewStuffModel::StateRole ).toInt() );
- QString actionText;
- switch( state )
- {
- case AtticaManager::Uninstalled:
- actionText = tr( "Install" );
- break;
- case AtticaManager::Installing:
- actionText = tr( "Installing" );
- break;
- case AtticaManager::Upgrading:
- actionText = tr( "Upgrading" );
- break;
- case AtticaManager::Failed:
- actionText = tr( "Failed" );
- break;
- case AtticaManager::Installed:
- actionText = tr( "Uninstall" );
- break;
- case AtticaManager::NeedsUpgrade:
- actionText = tr( "Upgrade" );
- break;
- }
-
- const int btnWidth = m_widestTextWidth + 7;
- const int leftEdge = opt.rect.width() - PADDING - btnWidth - 3;
- const QRect btnRect( leftEdge, center - ( installMetrics.height() + 4 ) / 2, btnWidth, installMetrics.height() + 4 );
- m_cachedButtonRects[ QPair(index.row(), index.column()) ] = btnRect;
-
- QPen saved = painter->pen();
- painter->setPen( opt.palette.color( QPalette::Active, QPalette::AlternateBase ) );
-
- QPainterPath btnPath;
- const int radius = 3;
- //btnPath.addRoundedRect( btnRect, 3, 3 );
- // draw top half gradient
- const int btnCenter = btnRect.bottom() - ( btnRect.height() / 2 );
- btnPath.moveTo( btnRect.left(), btnCenter );
- btnPath.lineTo( btnRect.left(), btnRect.top() + radius );
- btnPath.quadTo( QPoint( btnRect.topLeft() ), QPoint( btnRect.left() + radius, btnRect.top() ) );
- btnPath.lineTo( btnRect.right() - radius, btnRect.top() );
- btnPath.quadTo( QPoint( btnRect.topRight() ), QPoint( btnRect.right(), btnRect.top() + radius ) );
- btnPath.lineTo( btnRect.right(),btnCenter );
- btnPath.lineTo( btnRect.left(), btnCenter );
-
- QLinearGradient g;
- g.setColorAt( 0, QColor(54, 127, 211) );
- g.setColorAt( 0.5, QColor(43, 104, 182) );
- //painter->setPen( bg.darker() );
- painter->fillPath( btnPath, g );
- //painter->drawPath( btnPath );
-
- btnPath = QPainterPath();
- btnPath.moveTo( btnRect.left(), btnCenter );
- btnPath.lineTo( btnRect.left(), btnRect.bottom() - radius );
- btnPath.quadTo( QPoint( btnRect.bottomLeft() ), QPoint( btnRect.left() + radius, btnRect.bottom() ) );
- btnPath.lineTo( btnRect.right() - radius, btnRect.bottom() );
- btnPath.quadTo( QPoint( btnRect.bottomRight() ), QPoint( btnRect.right(), btnRect.bottom() - radius ) );
- btnPath.lineTo( btnRect.right(), btnCenter );
- btnPath.lineTo( btnRect.left(), btnCenter );
-
- g.setColorAt( 0, QColor(34, 85, 159) );
- g.setColorAt( 0.5, QColor(35, 79, 147) );
- painter->fillPath( btnPath, g );
-
- painter->setFont( installFont );
- painter->drawText( btnRect, Qt::AlignCenter, actionText );
-
- painter->setPen( saved );
-
- // rating stars
- int rating = index.data( GetNewStuffModel::RatingRole ).toInt();
- const int ratingWidth = 5 * ( m_ratingStarPositive.width() + PADDING_BETWEEN_STARS );
- int runningEdge = ( btnRect.right() - btnRect.width() / 2 ) - ratingWidth / 2;
- for ( int i = 1; i < 6; i++ )
- {
- QRect r( runningEdge, btnRect.top() - m_ratingStarPositive.height() - PADDING, m_ratingStarPositive.width(), m_ratingStarPositive.height() );
- if ( i == 1 )
- m_cachedStarRects[ QPair(index.row(), index.column()) ] = r;
-
- const bool userHasRated = index.data( GetNewStuffModel::UserHasRatedRole ).toBool();
- if ( !userHasRated && // Show on-hover animation if the user hasn't rated it yet, and is hovering over it
- m_hoveringOver > -1 &&
- m_hoveringItem == index )
- {
- if ( i <= m_hoveringOver ) // positive star
- painter->drawPixmap( r, m_onHoverStar );
- else
- painter->drawPixmap( r, m_ratingStarNegative );
- }
- else
- {
- if ( i <= rating ) // positive or rated star
- {
- if ( userHasRated )
- painter->drawPixmap( r, m_onHoverStar );
- else
- painter->drawPixmap( r, m_ratingStarPositive );
- }
- else
- painter->drawPixmap( r, m_ratingStarNegative );
- }
- runningEdge += m_ratingStarPositive.width() + PADDING_BETWEEN_STARS;
- }
-
- // downloaded num times, underneath button
- QString count = tr( "%1 downloads" ).arg( index.data( GetNewStuffModel::DownloadCounterRole ).toInt() );
- const QRect countRect( btnRect.left(), btnRect.bottom() + PADDING, btnRect.width(), opt.rect.bottom() - PADDING - btnRect.bottom() );
- QFont countFont = descFont;
- countFont.setPointSize( countFont.pointSize() - 2 );
- countFont.setBold( true );
- painter->setFont( countFont );
- painter->drawText( countRect, Qt::AlignCenter | Qt::TextWordWrap, count );
-
- // author and version
- QString author = index.data( GetNewStuffModel::AuthorRole ).toString();
- const int authorWidth = authorMetrics.width( author );
- const int topTextLine = opt.rect.top() + PADDING;
- const QRect authorRect( btnRect.x() - 3*PADDING - authorWidth, topTextLine, authorWidth + 6, authorMetrics.height() );
- painter->setFont( authorFont );
- painter->drawText( authorRect, Qt::AlignCenter, author );
-
- const QRect versionRect = authorRect.translated( 0, authorRect.height() );
- QString version = index.data( GetNewStuffModel::VersionRole ).toString();
- painter->drawText( versionRect, Qt::AlignCenter, version );
-
- // title
- QString title = index.data( Qt::DisplayRole ).toString();
- const int rightTitleEdge = authorRect.left() - PADDING;
- const int leftTitleEdge = pixmapRect.right() + PADDING;
- const QRect textRect( leftTitleEdge, topTextLine, rightTitleEdge - leftTitleEdge, versionRect.bottom() - opt.rect.top() - PADDING );
- painter->setFont( titleFont );
- painter->drawText( textRect, Qt::AlignVCenter | Qt::AlignLeft, title );
-
- // description
- QString desc = index.data( GetNewStuffModel::DescriptionRole ).toString();
- const int descWidth = btnRect.left() - leftTitleEdge - PADDING;
- const QRect descRect( leftTitleEdge, versionRect.bottom(), descWidth, opt.rect.bottom() - versionRect.bottom() + PADDING );
- painter->setFont( descFont );
- painter->drawText( descRect, Qt::AlignLeft | Qt::TextWordWrap, desc );
-}
-
-
-QSize
-GetNewStuffDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const
-{
- Q_UNUSED( option );
- Q_UNUSED( index );
- return QSize( 200, SIZEHINT_HEIGHT );
-}
-
-bool
-GetNewStuffDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index )
-{
- Q_UNUSED( option );
-
- if ( event->type() != QEvent::MouseButtonRelease &&
- event->type() != QEvent::MouseMove )
- return false;
-
- if ( event->type() == QEvent::MouseButtonRelease && m_cachedButtonRects.contains( QPair( index.row(), index.column() ) ) )
- {
- QRect rect = m_cachedButtonRects[ QPair( index.row(), index.column() ) ];
- QMouseEvent* me = static_cast< QMouseEvent* >( event );
-
- if ( rect.contains( me->pos() ) )
- {
- model->setData( index, true );
-
- return true;
- }
- }
-
- if ( m_cachedStarRects.contains( QPair( index.row(), index.column() ) ) )
- {
- QRect fullStars = m_cachedStarRects[ QPair( index.row(), index.column() ) ];
- const int starsWidth = 5 * ( m_ratingStarPositive.width() + PADDING_BETWEEN_STARS );
- fullStars.setWidth( starsWidth );
-
- QMouseEvent* me = static_cast< QMouseEvent* >( event );
-
- if ( fullStars.contains( me->pos() ) )
- {
- const int eachStar = starsWidth / 5;
- const int clickOffset = me->pos().x() - fullStars.x();
- const int whichStar = (clickOffset / eachStar) + 1;
-
- if ( event->type() == QEvent::MouseButtonRelease )
- {
- model->setData( index, whichStar, GetNewStuffModel::RatingRole );
- }
- else if ( event->type() == QEvent::MouseMove )
- {
- // 0-indexed
- m_hoveringOver = whichStar;
- m_hoveringItem = index;
- }
-
- return true;
- }
- }
-
- if ( m_hoveringOver > -1 )
- {
- emit update( m_hoveringItem );
- m_hoveringOver = -1;
- m_hoveringItem = QPersistentModelIndex();
- }
- return false;
-}
diff --git a/src/GetNewStuffDialog.cpp b/src/GetNewStuffDialog.cpp
deleted file mode 100644
index da3f0891f..000000000
--- a/src/GetNewStuffDialog.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/* === This file is part of Tomahawk Player - ===
- *
- * Copyright 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 "GetNewStuffDialog.h"
-
-#include "ui_GetNewStuffDialog.h"
-#include "GetNewStuffDelegate.h"
-#include "GetNewStuffModel.h"
-
-GetNewStuffDialog::GetNewStuffDialog( QWidget* parent, Qt::WindowFlags f )
- : QDialog( parent, f )
- , ui( new Ui::GetNewStuffDialog )
- , m_model( new GetNewStuffModel( this ) )
-{
- ui->setupUi( this );
-
- ui->listView->setModel( m_model );
- GetNewStuffDelegate* del = new GetNewStuffDelegate( ui->listView );
- connect( del, SIGNAL( update( QModelIndex ) ), ui->listView, SLOT( update( QModelIndex ) ) );
- ui->listView->setItemDelegate( del );
- ui->listView->setVerticalScrollMode( QAbstractItemView::ScrollPerPixel );
-
- ui->listView->setMouseTracking( true );
-
- setMinimumSize( 560, 350 );
-
-#ifdef Q_WS_MAC
- setMaximumSize( 560, 350 );
- setSizeGripEnabled( false );
-
- ui->listView->setAttribute( Qt::WA_MacShowFocusRect, false );
-#endif
-}
-
-
-GetNewStuffDialog::~GetNewStuffDialog()
-{
- delete ui;
-}
diff --git a/src/GetNewStuffDialog.ui b/src/GetNewStuffDialog.ui
deleted file mode 100644
index 1686a8200..000000000
--- a/src/GetNewStuffDialog.ui
+++ /dev/null
@@ -1,67 +0,0 @@
-
-
- GetNewStuffDialog
-
-
-
- 0
- 0
- 449
- 282
-
-
-
- Download New Resolvers
-
-
- -
-
-
- -
-
-
- Qt::Horizontal
-
-
- QDialogButtonBox::Cancel|QDialogButtonBox::Ok
-
-
-
-
-
-
-
-
- buttonBox
- accepted()
- GetNewStuffDialog
- accept()
-
-
- 248
- 254
-
-
- 157
- 274
-
-
-
-
- buttonBox
- rejected()
- GetNewStuffDialog
- reject()
-
-
- 316
- 260
-
-
- 286
- 274
-
-
-
-
-
diff --git a/src/GetNewStuffModel.cpp b/src/GetNewStuffModel.cpp
deleted file mode 100644
index 405ca968b..000000000
--- a/src/GetNewStuffModel.cpp
+++ /dev/null
@@ -1,156 +0,0 @@
-/* === 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 "GetNewStuffModel.h"
-
-#include "utils/tomahawkutils.h"
-#include "utils/logger.h"
-
-#include
-#include
-#include "AtticaManager.h"
-
-GetNewStuffModel::GetNewStuffModel( QObject* parent )
- : QAbstractListModel ( parent )
-{
-
- if ( AtticaManager::instance()->resolversLoaded() )
- m_contentList = AtticaManager::instance()->resolvers();
-
- connect( AtticaManager::instance(), SIGNAL( resolversReloaded( Attica::Content::List ) ), this, SLOT( resolversReloaded( Attica::Content::List ) ) );
- connect( AtticaManager::instance(), SIGNAL( resolverStateChanged( QString ) ), this, SLOT( resolverStateChanged( QString ) ) );
-
-}
-
-GetNewStuffModel::~GetNewStuffModel()
-{
-}
-
-void
-GetNewStuffModel::resolversReloaded( const Attica::Content::List& resolvers )
-{
- beginResetModel();
- m_contentList = resolvers;
- endResetModel();
-}
-
-void
-GetNewStuffModel::resolverStateChanged( const QString& resolverId )
-{
- for ( int i = 0; i < m_contentList.count(); i++ )
- {
- const Attica::Content resolver = m_contentList[ i ];
- if ( resolver.id() == resolverId )
- {
- QModelIndex idx = index( i, 0, QModelIndex() );
- emit dataChanged( idx, idx );
- }
- }
-}
-
-
-QVariant
-GetNewStuffModel::data( const QModelIndex& index, int role ) const
-{
- if ( !index.isValid() || !hasIndex( index.row(), index.column(), index.parent() ) )
- return QVariant();
-
- Attica::Content resolver = m_contentList[ index.row() ];
- switch ( role )
- {
- case Qt::DisplayRole:
- return resolver.name();
- case Qt::DecorationRole:
- return QVariant::fromValue< QPixmap >( AtticaManager::instance()->iconForResolver( resolver ) );
- case DownloadUrlRole:
- // TODO
- return QUrl();
- case RatingRole:
- return resolver.rating() / 20; // rating is out of 100
- case DownloadCounterRole:
- return resolver.downloads();
- case VersionRole:
- return resolver.version();
- case DescriptionRole:
- return resolver.description();
- case TypeRole:
- return ResolverType;
- case AuthorRole:
- return resolver.author();
- case StateRole:
- return (int)AtticaManager::instance()->resolverState( resolver );
- case UserHasRatedRole:
- return AtticaManager::instance()->userHasRated( resolver );
- }
- return QVariant();
-}
-
-int
-GetNewStuffModel::rowCount( const QModelIndex& parent ) const
-{
- Q_UNUSED( parent );
- return m_contentList.count();
-}
-
-bool
-GetNewStuffModel::setData( const QModelIndex &index, const QVariant &value, int role )
-{
- Q_UNUSED( value );
- if ( !hasIndex( index.row(), index.column(), index.parent() ) )
- return false;
-
-
- Attica::Content resolver = m_contentList[ index.row() ];
- AtticaManager::ResolverState state = AtticaManager::instance()->resolverState( resolver );
- if ( role == Qt::EditRole )
- {
- switch( state )
- {
- case AtticaManager::Uninstalled:
- // install
- AtticaManager::instance()->installResolver( resolver );
- break;
- case AtticaManager::Installing:
- case AtticaManager::Upgrading:
- // Do nothing, busy
- break;
- case AtticaManager::Installed:
- // Uninstall
- AtticaManager::instance()->uninstallResolver( resolver );
- break;
- case AtticaManager::NeedsUpgrade:
- AtticaManager::instance()->upgradeResolver( resolver );
- break;
- default:
- //FIXME -- this handles e.g. Failed
- break;
- };
- } else if ( role == RatingRole )
- {
- // For now only allow rating if a resolver is installed!
- if ( state != AtticaManager::Installed && state != AtticaManager::NeedsUpgrade )
- return false;
- if ( AtticaManager::instance()->userHasRated( resolver ) )
- return false;
- m_contentList[ index.row() ].setRating( value.toInt() * 20 );
- AtticaManager::instance()->uploadRating( m_contentList[ index.row() ] );
- }
- emit dataChanged( index, index );
-
- return true;
-}
diff --git a/src/GetNewStuffModel.h b/src/GetNewStuffModel.h
deleted file mode 100644
index 378057e1e..000000000
--- a/src/GetNewStuffModel.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/* === 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 GETNEWSTUFFMODEL_H
-#define GETNEWSTUFFMODEL_H
-
-#include
-
-#include
-#include
-
-class GetNewStuffModel: public QAbstractListModel
-{
- Q_OBJECT
-public:
- enum NewStuffRoles {
- // DisplayRole is title
- // DecorationRole is qicon for item
- DownloadUrlRole = Qt::UserRole + 1,
- RatingRole = Qt::UserRole + 2,
- DownloadCounterRole = Qt::UserRole + 3,
- VersionRole = Qt::UserRole + 4,
- DescriptionRole = Qt::UserRole + 5,
- TypeRole = Qt::UserRole + 6, // Category in attica-speak. What sort of item this is (resolver, etc).
- AuthorRole = Qt::UserRole + 7,
- StateRole = Qt::UserRole + 8,
- UserHasRatedRole = Qt::UserRole + 9
- };
-
- enum Types {
- ResolverType = 0,
- };
-
- explicit GetNewStuffModel( QObject* parent = 0 );
- virtual ~GetNewStuffModel();
-
- virtual QVariant data( const QModelIndex& index, int role = Qt::DisplayRole ) const;
- virtual int rowCount( const QModelIndex& parent = QModelIndex() ) const;
- virtual bool setData( const QModelIndex &index, const QVariant &value, int role );
-
-private slots:
- void resolversReloaded( const Attica::Content::List& );
- void resolverStateChanged( const QString& resolverId );
-
-private:
- Attica::Content::List m_contentList;
-};
-
-#endif // GETNEWSTUFFMODEL_H
diff --git a/src/sip/CMakeLists.txt b/src/accounts/CMakeLists.txt
similarity index 54%
rename from src/sip/CMakeLists.txt
rename to src/accounts/CMakeLists.txt
index 6857d099c..c7d709337 100644
--- a/src/sip/CMakeLists.txt
+++ b/src/accounts/CMakeLists.txt
@@ -1,9 +1,10 @@
+
IF( LIBJREEN_FOUND )
- ADD_SUBDIRECTORY( jabber )
-ENDIF( LIBJREEN_FOUND )
+ add_subdirectory( xmpp )
+ENDIF()
IF( QTWEETLIB_FOUND AND BUILD_GUI )
ADD_SUBDIRECTORY( twitter )
ENDIF()
-ADD_SUBDIRECTORY( zeroconf )
+ADD_SUBDIRECTORY( zeroconf )
\ No newline at end of file
diff --git a/src/GetNewStuffDialog.h b/src/accounts/accountdllmacro.h
similarity index 61%
rename from src/GetNewStuffDialog.h
rename to src/accounts/accountdllmacro.h
index a0e195a8d..bca08fc02 100644
--- a/src/GetNewStuffDialog.h
+++ b/src/accounts/accountdllmacro.h
@@ -1,6 +1,6 @@
/* === This file is part of Tomahawk Player - ===
*
- * Copyright 2011, Leo Franchi
+ * Copyright 2010-2011, Christian Muehlhaeuser
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -16,26 +16,17 @@
* along with Tomahawk. If not, see .
*/
-#ifndef GETNEWSTUFFDIALOG_H
-#define GETNEWSTUFFDIALOG_H
+#ifndef ACCOUNTDLLMACRO_H
+#define ACCOUNTDLLMACRO_H
-#include
+#ifdef Q_WS_WIN
+ #ifdef ACCOUNTDLLEXPORT_PRO
+ #define ACCOUNTDLLEXPORT __declspec(dllexport)
+ #else
+ #define ACCOUNTDLLEXPORT __declspec(dllimport)
+ #endif
+#else
+ #define ACCOUNTDLLEXPORT
+#endif
-class GetNewStuffModel;
-namespace Ui {
- class GetNewStuffDialog;
-}
-
-class GetNewStuffDialog : public QDialog
-{
- Q_OBJECT
-public:
- explicit GetNewStuffDialog( QWidget *parent = 0, Qt::WindowFlags f = 0 );
- ~GetNewStuffDialog();
-
-private:
- Ui::GetNewStuffDialog *ui;
- GetNewStuffModel* m_model;
-};
-
-#endif // GETNEWSTUFFDIALOG_H
+#endif
diff --git a/src/sip/twitter/CMakeLists.txt b/src/accounts/twitter/CMakeLists.txt
similarity index 58%
rename from src/sip/twitter/CMakeLists.txt
rename to src/accounts/twitter/CMakeLists.txt
index fc6037fb2..3ad17a72a 100644
--- a/src/sip/twitter/CMakeLists.txt
+++ b/src/accounts/twitter/CMakeLists.txt
@@ -4,21 +4,23 @@ include( ${QT_USE_FILE} )
add_definitions( ${QT_DEFINITIONS} )
add_definitions( -DQT_PLUGIN )
add_definitions( -DQT_SHARED )
-add_definitions( -DSIPDLLEXPORT_PRO )
+add_definitions( -DACCOUNTDLLEXPORT_PRO )
-set( twitterSources
- twitter.cpp
+set( twitterAccountSources
+ twitteraccount.cpp
twitterconfigwidget.cpp
tomahawkoauthtwitter.cpp
+ sip/twittersip.cpp
)
-set( twitterHeaders
- twitter.h
+set( twitterAccountHeaders
+ twitteraccount.h
twitterconfigwidget.h
tomahawkoauthtwitter.h
+ sip/twittersip.h
)
-set( twitterUI
+set( twitterAccountUI
twitterconfigwidget.ui
)
@@ -27,10 +29,10 @@ include_directories( . ${CMAKE_CURRENT_BINARY_DIR} ..
${QTWEETLIB_INCLUDE_DIR}
)
+qt4_wrap_cpp( twitterAccountMoc ${twitterAccountHeaders} )
+qt4_wrap_ui( twitterAccountUI_H ${twitterAccountUI} )
qt4_add_resources( RC_SRCS "resources.qrc" )
-qt4_wrap_cpp( twitterMoc ${twitterHeaders} )
-qt4_wrap_ui( twitterUI_H ${twitterUI} )
-add_library( tomahawk_siptwitter SHARED ${twitterUI_H} ${twitterSources} ${twitterMoc} ${RC_SRCS} )
+add_library( tomahawk_account_twitter MODULE ${twitterAccountUI_H} ${twitterAccountSources} ${twitterAccountMoc} ${RC_SRCS} )
IF( WIN32 )
SET( OS_SPECIFIC_LINK_LIBRARIES
@@ -40,7 +42,7 @@ SET( OS_SPECIFIC_LINK_LIBRARIES
)
ENDIF( WIN32 )
-target_link_libraries( tomahawk_siptwitter
+target_link_libraries( tomahawk_account_twitter
${TOMAHAWK_LIBRARIES}
${QTWEETLIB_LIBRARIES}
${QT_LIBRARIES}
@@ -51,4 +53,4 @@ IF( APPLE )
# SET( CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS} "-undefined dynamic_lookup" )
ENDIF( APPLE )
-install( TARGETS tomahawk_siptwitter DESTINATION ${CMAKE_INSTALL_LIBDIR} )
+install( TARGETS tomahawk_account_twitter DESTINATION ${CMAKE_INSTALL_LIBDIR} )
diff --git a/src/sip/twitter/resources.qrc b/src/accounts/twitter/resources.qrc
similarity index 100%
rename from src/sip/twitter/resources.qrc
rename to src/accounts/twitter/resources.qrc
diff --git a/src/accounts/twitter/sip/twittersip.cpp b/src/accounts/twitter/sip/twittersip.cpp
new file mode 100644
index 000000000..ee65f50ff
--- /dev/null
+++ b/src/accounts/twitter/sip/twittersip.cpp
@@ -0,0 +1,714 @@
+/* === This file is part of Tomahawk Player - ===
+ *
+ * Copyright 2010-2011, Christian Muehlhaeuser
+ * Copyright 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 "twittersip.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include "utils/logger.h"
+#include "accounts/twitter/tomahawkoauthtwitter.h"
+#include
+
+static QString s_gotTomahawkRegex = QString( "^(@[a-zA-Z0-9]+ )?(Got Tomahawk\\?) (\\{[a-fA-F0-9\\-]+\\}) (.*)$" );
+
+TwitterSipPlugin::TwitterSipPlugin( Tomahawk::Accounts::Account* account )
+ : SipPlugin( account )
+ , m_checkTimer( this )
+ , m_connectTimer( this )
+ , m_dmPollTimer( this )
+ , m_cachedFriendsSinceId( 0 )
+ , m_cachedMentionsSinceId( 0 )
+ , m_cachedDirectMessagesSinceId( 0 )
+ , m_cachedPeers()
+ , m_keyCache()
+ , m_state( Tomahawk::Accounts::Account::Disconnected )
+{
+ qDebug() << Q_FUNC_INFO;
+
+ connect( account, SIGNAL( nowAuthenticated( const QWeakPointer< TomahawkOAuthTwitter > &, const QTweetUser & ) ), SLOT( accountAuthenticated( const QWeakPointer< TomahawkOAuthTwitter > &, const QTweetUser & ) ) );
+
+ m_configuration = account->configuration();
+ qDebug() << "SIP configuration:" << m_configuration << m_configuration[ "cachedpeers" ];
+ if ( Database::instance()->dbid() != m_account->configuration()[ "saveddbid" ].toString() )
+ {
+ m_configuration[ "cachedpeers" ] = QVariantHash();
+ m_configuration[ "saveddbid" ] = Database::instance()->dbid();
+ syncConfig();
+ }
+
+ m_checkTimer.setInterval( 180000 );
+ m_checkTimer.setSingleShot( false );
+ connect( &m_checkTimer, SIGNAL( timeout() ), SLOT( checkTimerFired() ) );
+
+ m_dmPollTimer.setInterval( 60000 );
+ m_dmPollTimer.setSingleShot( false );
+ connect( &m_dmPollTimer, SIGNAL( timeout() ), SLOT( pollDirectMessages() ) );
+
+ m_connectTimer.setInterval( 180000 );
+ m_connectTimer.setSingleShot( false );
+ connect( &m_connectTimer, SIGNAL( timeout() ), SLOT( connectTimerFired() ) );
+}
+
+
+bool
+TwitterSipPlugin::isValid() const
+{
+ return m_account->enabled() && m_account->isAuthenticated() && !m_cachedTwitterAuth.isNull();
+}
+
+
+Tomahawk::Accounts::Account::ConnectionState
+TwitterSipPlugin::connectionState() const
+{
+ return m_state;
+}
+
+
+void
+TwitterSipPlugin::checkSettings()
+{
+ configurationChanged();
+}
+
+
+void
+TwitterSipPlugin::connectPlugin()
+{
+ tDebug() << Q_FUNC_INFO;
+ if ( !m_account->enabled() )
+ {
+ tDebug() << Q_FUNC_INFO << "account isn't enabled";
+ return;
+ }
+
+ m_cachedPeers = m_configuration[ "cachedpeers" ].toHash();
+ QStringList peerList = m_cachedPeers.keys();
+ qStableSort( peerList.begin(), peerList.end() );
+
+ if ( !m_account->isAuthenticated() )
+ {
+ tDebug() << Q_FUNC_INFO << "account isn't authenticated, attempting";
+ m_account->authenticate();
+ }
+
+ m_state = Tomahawk::Accounts::Account::Connecting;
+ emit stateChanged( m_state );
+}
+
+
+void
+TwitterSipPlugin::disconnectPlugin()
+{
+ tDebug() << Q_FUNC_INFO;
+ m_checkTimer.stop();
+ m_connectTimer.stop();
+ m_dmPollTimer.stop();
+ if( !m_friendsTimeline.isNull() )
+ delete m_friendsTimeline.data();
+ if( !m_mentions.isNull() )
+ delete m_mentions.data();
+ if( !m_directMessages.isNull() )
+ delete m_directMessages.data();
+ if( !m_directMessageNew.isNull() )
+ delete m_directMessageNew.data();
+ if( !m_directMessageDestroy.isNull() )
+ delete m_directMessageDestroy.data();
+
+ m_cachedTwitterAuth.clear();
+
+ m_configuration[ "cachedpeers" ] = m_cachedPeers;
+ syncConfig();
+ m_cachedPeers.empty();
+ m_state = Tomahawk::Accounts::Account::Disconnected;
+ emit stateChanged( m_state );
+}
+
+void
+TwitterSipPlugin::accountAuthenticated( const QWeakPointer< TomahawkOAuthTwitter > &twitterAuth, const QTweetUser &user )
+{
+ Q_UNUSED( user );
+
+ if ( !m_account->enabled() || !m_account->isAuthenticated() )
+ return;
+
+ m_cachedTwitterAuth = twitterAuth;
+
+ m_friendsTimeline = QWeakPointer( new QTweetFriendsTimeline( m_cachedTwitterAuth.data(), this ) );
+ m_mentions = QWeakPointer( new QTweetMentions( m_cachedTwitterAuth.data(), this ) );
+ m_directMessages = QWeakPointer( new QTweetDirectMessages( m_cachedTwitterAuth.data(), this ) );
+ m_directMessageNew = QWeakPointer( new QTweetDirectMessageNew( m_cachedTwitterAuth.data(), this ) );
+ m_directMessageDestroy = QWeakPointer( new QTweetDirectMessageDestroy( m_cachedTwitterAuth.data(), this ) );
+ connect( m_friendsTimeline.data(), SIGNAL( parsedStatuses(const QList< QTweetStatus > &) ), SLOT( friendsTimelineStatuses(const QList &) ) );
+ connect( m_mentions.data(), SIGNAL( parsedStatuses(const QList< QTweetStatus > &) ), SLOT( mentionsStatuses(const QList &) ) );
+ connect( m_directMessages.data(), SIGNAL( parsedDirectMessages(const QList &)), SLOT( directMessages(const QList &) ) );
+ connect( m_directMessageNew.data(), SIGNAL( parsedDirectMessage(const QTweetDMStatus &)), SLOT( directMessagePosted(const QTweetDMStatus &) ) );
+ connect( m_directMessageNew.data(), SIGNAL( error(QTweetNetBase::ErrorCode, const QString &) ), SLOT( directMessagePostError(QTweetNetBase::ErrorCode, const QString &) ) );
+ connect( m_directMessageDestroy.data(), SIGNAL( parsedDirectMessage(const QTweetDMStatus &) ), SLOT( directMessageDestroyed(const QTweetDMStatus &) ) );
+ m_state = Tomahawk::Accounts::Account::Connected;
+ emit stateChanged( m_state );
+ QStringList peerList = m_cachedPeers.keys();
+ qStableSort( peerList.begin(), peerList.end() );
+ registerOffers( peerList );
+ m_connectTimer.start();
+ m_checkTimer.start();
+ m_dmPollTimer.start();
+
+ QMetaObject::invokeMethod( this, "checkTimerFired", Qt::AutoConnection );
+ QTimer::singleShot( 20000, this, SLOT( connectTimerFired() ) );
+}
+
+
+void
+TwitterSipPlugin::checkTimerFired()
+{
+ if ( !isValid() )
+ return;
+
+ if ( m_cachedFriendsSinceId == 0 )
+ m_cachedFriendsSinceId = m_configuration[ "cachedfriendssinceid" ].toLongLong();
+
+ qDebug() << "TwitterSipPlugin looking at friends timeline since id " << m_cachedFriendsSinceId;
+
+ if ( !m_friendsTimeline.isNull() )
+ m_friendsTimeline.data()->fetch( m_cachedFriendsSinceId, 0, 800 );
+
+ if ( m_cachedMentionsSinceId == 0 )
+ m_cachedMentionsSinceId = m_configuration[ "cachedmentionssinceid" ].toLongLong();
+
+ qDebug() << "TwitterSipPlugin looking at mentions timeline since id " << m_cachedMentionsSinceId;
+
+ if ( !m_mentions.isNull() )
+ m_mentions.data()->fetch( m_cachedMentionsSinceId, 0, 800 );
+}
+
+
+void
+TwitterSipPlugin::registerOffers( const QStringList &peerList )
+{
+ if ( !isValid() )
+ return;
+
+ foreach( QString screenName, peerList )
+ {
+ QVariantHash peerData = m_cachedPeers[screenName].toHash();
+
+ if ( peerData.contains( "onod" ) && peerData["onod"] != Database::instance()->dbid() )
+ {
+ m_cachedPeers.remove( screenName );
+ m_configuration[ "cachedpeers" ] = m_cachedPeers;
+ syncConfig();
+ }
+
+ if ( Servent::instance()->connectedToSession( peerData["node"].toString() ) )
+ {
+ peerData["lastseen"] = QDateTime::currentMSecsSinceEpoch();
+ m_cachedPeers[screenName] = peerData;
+ m_configuration[ "cachedpeers" ] = m_cachedPeers;
+ syncConfig();
+ qDebug() << Q_FUNC_INFO << " already connected";
+ continue;
+ }
+ else if ( QDateTime::currentMSecsSinceEpoch() - peerData["lastseen"].toLongLong() > 1209600000 ) // 2 weeks
+ {
+ qDebug() << Q_FUNC_INFO << " aging peer " << screenName << " out of cache";
+ m_cachedPeers.remove( screenName );
+ m_configuration[ "cachedpeers" ] = m_cachedPeers;
+ syncConfig();
+ m_cachedAvatars.remove( screenName );
+ continue;
+ }
+
+ if ( !peerData.contains( "host" ) || !peerData.contains( "port" ) || !peerData.contains( "pkey" ) )
+ {
+ qDebug() << "TwitterSipPlugin does not have host, port and/or pkey values for " << screenName << " (this is usually *not* a bug or problem but a normal part of the process)";
+ continue;
+ }
+
+ QMetaObject::invokeMethod( this, "registerOffer", Q_ARG( QString, screenName ), Q_ARG( QVariantHash, peerData ) );
+ }
+}
+
+
+void
+TwitterSipPlugin::connectTimerFired()
+{
+ tDebug() << Q_FUNC_INFO << " beginning";
+ if ( !isValid() || m_cachedPeers.isEmpty() )
+ {
+ if ( !isValid() )
+ tDebug() << Q_FUNC_INFO << " is not valid";
+ if ( m_cachedPeers.isEmpty() )
+ tDebug() << Q_FUNC_INFO << " has empty cached peers";
+ return;
+ }
+
+ tDebug() << Q_FUNC_INFO << " continuing";
+ QString myScreenName = m_configuration[ "screenname" ].toString();
+ QStringList peerList = m_cachedPeers.keys();
+ qStableSort( peerList.begin(), peerList.end() );
+ registerOffers( peerList );
+}
+
+void
+TwitterSipPlugin::parseGotTomahawk( const QRegExp ®ex, const QString &screenName, const QString &text )
+{
+ QString myScreenName = m_configuration[ "screenname" ].toString();
+ qDebug() << "TwitterSipPlugin found an exact matching Got Tomahawk? mention or direct message from user " << screenName << ", now parsing";
+ regex.exactMatch( text );
+ if ( text.startsWith( '@' ) && regex.captureCount() >= 2 && regex.cap( 1 ) != QString( '@' + myScreenName ) )
+ {
+ qDebug() << "TwitterSipPlugin skipping mention because it's directed @someone that isn't us";
+ return;
+ }
+
+ QString node;
+ for ( int i = 0; i < regex.captureCount(); ++i )
+ {
+ if ( regex.cap( i ) == QString( "Got Tomahawk?" ) )
+ {
+ QString nodeCap = regex.cap( i + 1 );
+ nodeCap.chop( 1 );
+ node = nodeCap.mid( 1 );
+ }
+ }
+ if ( node.isEmpty() )
+ {
+ qDebug() << "TwitterSipPlugin could not parse node out of the tweet";
+ return;
+ }
+ else
+ qDebug() << "TwitterSipPlugin parsed node " << node << " out of the tweet";
+
+ if ( node == Database::instance()->dbid() )
+ {
+ qDebug() << "My dbid found; ignoring";
+ return;
+ }
+
+ QVariantHash peerData;
+ if( m_cachedPeers.contains( screenName ) )
+ {
+ peerData = m_cachedPeers[screenName].toHash();
+ //force a re-send of info but no need to re-register
+ peerData["resend"] = QVariant::fromValue< bool >( true );
+ if ( peerData["node"].toString() != node )
+ peerData["rekey"] = QVariant::fromValue< bool >( true );
+ }
+ peerData["node"] = QVariant::fromValue< QString >( node );
+ QMetaObject::invokeMethod( this, "registerOffer", Q_ARG( QString, screenName ), Q_ARG( QVariantHash, peerData ) );
+}
+
+void
+TwitterSipPlugin::friendsTimelineStatuses( const QList< QTweetStatus > &statuses )
+{
+ tDebug() << Q_FUNC_INFO;
+ QRegExp regex( s_gotTomahawkRegex, Qt::CaseSensitive, QRegExp::RegExp2 );
+
+ QHash< QString, QTweetStatus > latestHash;
+ foreach ( QTweetStatus status, statuses )
+ {
+ if ( !regex.exactMatch( status.text() ) )
+ continue;
+
+ if ( !latestHash.contains( status.user().screenName() ) )
+ latestHash[status.user().screenName()] = status;
+ else
+ {
+ if ( status.id() > latestHash[status.user().screenName()].id() )
+ latestHash[status.user().screenName()] = status;
+ }
+ }
+
+ foreach( QTweetStatus status, latestHash.values() )
+ {
+ if ( status.id() > m_cachedFriendsSinceId )
+ m_cachedFriendsSinceId = status.id();
+
+ tDebug() << "TwitterSipPlugin checking mention from " << status.user().screenName() << " with content " << status.text();
+ parseGotTomahawk( regex, status.user().screenName(), status.text() );
+ }
+
+ m_configuration[ "cachedfriendssinceid" ] = m_cachedFriendsSinceId;
+ syncConfig();
+}
+
+void
+TwitterSipPlugin::mentionsStatuses( const QList< QTweetStatus > &statuses )
+{
+ tDebug() << Q_FUNC_INFO;
+ QRegExp regex( s_gotTomahawkRegex, Qt::CaseSensitive, QRegExp::RegExp2 );
+
+ QHash< QString, QTweetStatus > latestHash;
+ foreach ( QTweetStatus status, statuses )
+ {
+ if ( !regex.exactMatch( status.text() ) )
+ continue;
+
+ if ( !latestHash.contains( status.user().screenName() ) )
+ latestHash[status.user().screenName()] = status;
+ else
+ {
+ if ( status.id() > latestHash[status.user().screenName()].id() )
+ latestHash[status.user().screenName()] = status;
+ }
+ }
+
+ foreach( QTweetStatus status, latestHash.values() )
+ {
+ if ( status.id() > m_cachedMentionsSinceId )
+ m_cachedMentionsSinceId = status.id();
+
+ tDebug() << "TwitterSipPlugin checking mention from " << status.user().screenName() << " with content " << status.text();
+ parseGotTomahawk( regex, status.user().screenName(), status.text() );
+ }
+
+ m_configuration[ "cachedmentionssinceid" ] = m_cachedMentionsSinceId;
+ syncConfig();
+}
+
+void
+TwitterSipPlugin::pollDirectMessages()
+{
+ if ( !isValid() )
+ return;
+
+ if ( m_cachedDirectMessagesSinceId == 0 )
+ m_cachedDirectMessagesSinceId = m_configuration[ "cacheddirectmessagessinceid" ].toLongLong();
+
+ tDebug() << "TwitterSipPlugin looking for direct messages since id " << m_cachedDirectMessagesSinceId;
+
+ if ( !m_directMessages.isNull() )
+ m_directMessages.data()->fetch( m_cachedDirectMessagesSinceId, 0, 800 );
+}
+
+void
+TwitterSipPlugin::directMessages( const QList< QTweetDMStatus > &messages )
+{
+ tDebug() << Q_FUNC_INFO;
+
+ QRegExp regex( s_gotTomahawkRegex, Qt::CaseSensitive, QRegExp::RegExp2 );
+ QString myScreenName = m_configuration[ "screenname" ].toString();
+
+ QHash< QString, QTweetDMStatus > latestHash;
+ foreach ( QTweetDMStatus status, messages )
+ {
+ if ( !regex.exactMatch( status.text() ) )
+ {
+ QStringList splitList = status.text().split(':');
+ if ( splitList.length() != 5 )
+ continue;
+ if ( splitList[0] != "TOMAHAWKPEER" )
+ continue;
+ if ( !splitList[1].startsWith( "Host=" ) || !splitList[2].startsWith( "Port=" ) || !splitList[3].startsWith( "Node=" ) || !splitList[4].startsWith( "PKey=" ) )
+ continue;
+ int port = splitList[2].mid( 5 ).toInt();
+ if ( port == 0 )
+ continue;
+ }
+
+ if ( !latestHash.contains( status.senderScreenName() ) )
+ latestHash[status.senderScreenName()] = status;
+ else
+ {
+ if ( status.id() > latestHash[status.senderScreenName()].id() )
+ latestHash[status.senderScreenName()] = status;
+ }
+ }
+
+ foreach( QTweetDMStatus status, latestHash.values() )
+ {
+ qDebug() << "TwitterSipPlugin checking direct message from " << status.senderScreenName() << " with content " << status.text();
+ if ( status.id() > m_cachedDirectMessagesSinceId )
+ m_cachedDirectMessagesSinceId = status.id();
+
+ if ( regex.exactMatch( status.text() ) )
+ parseGotTomahawk( regex, status.sender().screenName(), status.text() );
+ else
+ {
+ QStringList splitList = status.text().split(':');
+ qDebug() << "TwitterSipPlugin found " << splitList.length() << " parts to the message; the parts are:";
+ foreach( QString part, splitList )
+ qDebug() << part;
+ //validity is checked above
+ int port = splitList[2].mid( 5 ).toInt();
+ QString host = splitList[1].mid( 5 );
+ QString node = splitList[3].mid( 5 );
+ QString pkey = splitList[4].mid( 5 );
+ QStringList splitNode = node.split('*');
+ if ( splitNode.length() != 2 )
+ {
+ qDebug() << "Old-style node info found, ignoring";
+ continue;
+ }
+ qDebug() << "TwitterSipPlugin found a peerstart message from " << status.senderScreenName() << " with host " << host << " and port " << port << " and pkey " << pkey << " and node " << splitNode[0] << " destined for node " << splitNode[1];
+
+
+ QVariantHash peerData = ( m_cachedPeers.contains( status.senderScreenName() ) ) ?
+ m_cachedPeers[status.senderScreenName()].toHash() :
+ QVariantHash();
+
+ peerData["host"] = QVariant::fromValue< QString >( host );
+ peerData["port"] = QVariant::fromValue< int >( port );
+ peerData["pkey"] = QVariant::fromValue< QString >( pkey );
+ peerData["node"] = QVariant::fromValue< QString >( splitNode[0] );
+ peerData["dirty"] = QVariant::fromValue< bool >( true );
+
+ QMetaObject::invokeMethod( this, "registerOffer", Q_ARG( QString, status.senderScreenName() ), Q_ARG( QVariantHash, peerData ) );
+
+ if ( Database::instance()->dbid().startsWith( splitNode[1] ) )
+ {
+ qDebug() << "TwitterSipPlugin found message destined for this node; destroying it";
+ if ( !m_directMessageDestroy.isNull() )
+ m_directMessageDestroy.data()->destroyMessage( status.id() );
+ }
+ }
+ }
+
+ m_configuration[ "cacheddirectmessagessinceid" ] = m_cachedDirectMessagesSinceId;
+ syncConfig();
+}
+
+void
+TwitterSipPlugin::registerOffer( const QString &screenName, const QVariantHash &peerData )
+{
+ qDebug() << Q_FUNC_INFO;
+
+ bool peersChanged = false;
+ bool needToSend = false;
+ bool needToAddToCache = false;
+
+ QString friendlyName = QString( '@' + screenName );
+
+ if ( !m_cachedAvatars.contains( screenName ) )
+ QMetaObject::invokeMethod( this, "fetchAvatar", Q_ARG( QString, screenName ) );
+
+ QVariantHash _peerData( peerData );
+
+ if ( _peerData.contains( "dirty" ) )
+ {
+ peersChanged = true;
+ _peerData.remove( "dirty" );
+ }
+
+ if ( _peerData.contains( "resend" ) )
+ {
+ needToSend = true;
+ peersChanged = true;
+ _peerData.remove( "resend" );
+ }
+
+ if ( !_peerData.contains( "okey" ) ||
+ !_peerData.contains( "onod" ) ||
+ ( _peerData.contains( "onod" ) && _peerData["onod"] != Database::instance()->dbid() ) )
+ {
+ QString okey = QUuid::createUuid().toString().split( '-' ).last();
+ okey.chop( 1 );
+ _peerData["okey"] = QVariant::fromValue< QString >( okey );
+ _peerData["onod"] = QVariant::fromValue< QString >( Database::instance()->dbid() );
+ peersChanged = true;
+ needToAddToCache = true;
+ needToSend = true;
+ }
+
+ if ( _peerData.contains( "rekey" ) || !m_keyCache.contains( _peerData["okey"].toString() ) )
+ {
+ _peerData.remove( "rekey" );
+ needToAddToCache = true;
+ }
+
+ if ( !_peerData.contains( "ohst" ) || !_peerData.contains( "oprt" ) ||
+ _peerData["ohst"].toString() != Servent::instance()->externalAddress() ||
+ _peerData["oprt"].toInt() != Servent::instance()->externalPort()
+ )
+ needToSend = true;
+
+ if( needToAddToCache && _peerData.contains( "node" ) )
+ {
+ qDebug() << "TwitterSipPlugin registering offer to " << friendlyName << " with node " << _peerData["node"].toString() << " and offeredkey " << _peerData["okey"].toString();
+ m_keyCache << Servent::instance()->createConnectionKey( friendlyName, _peerData["node"].toString(), _peerData["okey"].toString(), false );
+ }
+
+ if( needToSend && _peerData.contains( "node") )
+ {
+ qDebug() << "TwitterSipPlugin needs to send and has node";
+ _peerData["ohst"] = QVariant::fromValue< QString >( Servent::instance()->externalAddress() );
+ _peerData["oprt"] = QVariant::fromValue< int >( Servent::instance()->externalPort() );
+ peersChanged = true;
+ if( !Servent::instance()->externalAddress().isEmpty() && !Servent::instance()->externalPort() == 0 )
+ QMetaObject::invokeMethod( this, "sendOffer", Q_ARG( QString, screenName ), Q_ARG( QVariantHash, _peerData ) );
+ else
+ qDebug() << "TwitterSipPlugin did not send offer because external address is " << Servent::instance()->externalAddress() << " and external port is " << Servent::instance()->externalPort();
+ }
+
+ if ( peersChanged )
+ {
+ _peerData["lastseen"] = QString::number( QDateTime::currentMSecsSinceEpoch() );
+ m_cachedPeers[screenName] = QVariant::fromValue< QVariantHash >( _peerData );
+ m_configuration[ "cachedpeers" ] = m_cachedPeers;
+ syncConfig();
+ }
+
+ if ( m_state == Tomahawk::Accounts::Account::Connected && _peerData.contains( "host" ) && _peerData.contains( "port" ) && _peerData.contains( "pkey" ) )
+ QMetaObject::invokeMethod( this, "makeConnection", Q_ARG( QString, screenName ), Q_ARG( QVariantHash, _peerData ) );
+
+}
+
+void
+TwitterSipPlugin::sendOffer( const QString &screenName, const QVariantHash &peerData )
+{
+ qDebug() << Q_FUNC_INFO;
+ QString offerString = QString( "TOMAHAWKPEER:Host=%1:Port=%2:Node=%3*%4:PKey=%5" ).arg( peerData["ohst"].toString() )
+ .arg( peerData["oprt"].toString() )
+ .arg( Database::instance()->dbid() )
+ .arg( peerData["node"].toString().left( 8 ) )
+ .arg( peerData["okey"].toString() );
+ qDebug() << "TwitterSipPlugin sending message to " << screenName << ": " << offerString;
+ if( !m_directMessageNew.isNull() )
+ m_directMessageNew.data()->post( screenName, offerString );
+}
+
+void
+TwitterSipPlugin::makeConnection( const QString &screenName, const QVariantHash &peerData )
+{
+ qDebug() << Q_FUNC_INFO;
+ if ( !peerData.contains( "host" ) || !peerData.contains( "port" ) || !peerData.contains( "pkey" ) || !peerData.contains( "node" ) ||
+ peerData["host"].toString().isEmpty() || peerData["port"].toString().isEmpty() || peerData["pkey"].toString().isEmpty() || peerData["node"].toString().isEmpty() )
+ {
+ qDebug() << "TwitterSipPlugin could not find host and/or port and/or pkey and/or node for peer " << screenName;
+ return;
+ }
+
+ if ( peerData["host"].toString() == Servent::instance()->externalAddress() &&
+ peerData["port"].toInt() == Servent::instance()->externalPort() )
+ {
+ qDebug() << "TwitterSipPlugin asked to make connection to our own host and port, ignoring " << screenName;
+ return;
+ }
+
+ QString friendlyName = QString( '@' + screenName );
+ if ( !Servent::instance()->connectedToSession( peerData["node"].toString() ) )
+ Servent::instance()->connectToPeer( peerData["host"].toString(),
+ peerData["port"].toString().toInt(),
+ peerData["pkey"].toString(),
+ friendlyName,
+ peerData["node"].toString() );
+}
+
+void
+TwitterSipPlugin::directMessagePosted( const QTweetDMStatus& message )
+{
+ qDebug() << Q_FUNC_INFO;
+ qDebug() << "TwitterSipPlugin sent message to " << message.recipientScreenName() << " containing: " << message.text();
+
+}
+
+void
+TwitterSipPlugin::directMessagePostError( QTweetNetBase::ErrorCode errorCode, const QString &message )
+{
+ Q_UNUSED( errorCode );
+ Q_UNUSED( message );
+ qDebug() << Q_FUNC_INFO;
+ qDebug() << "TwitterSipPlugin received an error posting direct message: " << m_directMessageNew.data()->lastErrorMessage();
+}
+
+void
+TwitterSipPlugin::directMessageDestroyed( const QTweetDMStatus& message )
+{
+ qDebug() << Q_FUNC_INFO;
+ qDebug() << "TwitterSipPlugin destroyed message " << message.text();
+}
+
+void
+TwitterSipPlugin::fetchAvatar( const QString& screenName )
+{
+ qDebug() << Q_FUNC_INFO;
+ if ( !isValid() )
+ return;
+
+ QTweetUserShow *userShowFetch = new QTweetUserShow( m_cachedTwitterAuth.data(), this );
+ connect( userShowFetch, SIGNAL( parsedUserInfo( QTweetUser ) ), SLOT( avatarUserDataSlot( QTweetUser ) ) );
+ userShowFetch->fetch( screenName );
+}
+
+void
+TwitterSipPlugin::avatarUserDataSlot( const QTweetUser &user )
+{
+ tDebug() << Q_FUNC_INFO;
+ if ( !isValid() || user.profileImageUrl().isEmpty())
+ return;
+
+ QNetworkRequest request( user.profileImageUrl() );
+ QNetworkReply *reply = m_cachedTwitterAuth.data()->networkAccessManager()->get( request );
+ reply->setProperty( "screenname", user.screenName() );
+ connect( reply, SIGNAL( finished() ), this, SLOT( profilePicReply() ) );
+}
+
+
+void
+TwitterSipPlugin::profilePicReply()
+{
+ tDebug() << Q_FUNC_INFO;
+ QNetworkReply *reply = qobject_cast< QNetworkReply* >( sender() );
+ if ( !reply || reply->error() != QNetworkReply::NoError || !reply->property( "screenname" ).isValid() )
+ {
+ tDebug() << Q_FUNC_INFO << " reply not valid or came back with error";
+ return;
+ }
+ QString screenName = reply->property( "screenname" ).toString();
+ QString friendlyName = '@' + screenName;
+ QByteArray rawData = reply->readAll();
+ QImage image;
+ image.loadFromData( rawData, "PNG" );
+ QPixmap pixmap = QPixmap::fromImage( image );
+ m_cachedAvatars[screenName] = pixmap;
+ emit avatarReceived( friendlyName, QPixmap::fromImage( image ) );
+}
+
+void
+TwitterSipPlugin::configurationChanged()
+{
+ tDebug() << Q_FUNC_INFO;
+ if ( m_state != Tomahawk::Accounts::Account::Disconnected )
+ m_account->deauthenticate();
+ connectPlugin();
+}
+
+
+void
+TwitterSipPlugin::syncConfig()
+{
+ m_account->setConfiguration( m_configuration );
+ m_account->sync();
+}
diff --git a/src/sip/twitter/twitter.h b/src/accounts/twitter/sip/twittersip.h
similarity index 59%
rename from src/sip/twitter/twitter.h
rename to src/accounts/twitter/sip/twittersip.h
index 3ca0688ca..09c18ac91 100644
--- a/src/sip/twitter/twitter.h
+++ b/src/accounts/twitter/sip/twittersip.h
@@ -1,6 +1,7 @@
/* === This file is part of Tomahawk Player - ===
*
* Copyright 2010-2011, Christian Muehlhaeuser
+ * Copyright 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
@@ -19,8 +20,6 @@
#ifndef TWITTER_H
#define TWITTER_H
-#include "twitterconfigwidget.h"
-
#include
#include
#include
@@ -34,50 +33,30 @@
#include
#include
-#include "../sipdllmacro.h"
+#include "accounts/accountdllmacro.h"
#include "sip/SipPlugin.h"
-#include "tomahawkoauthtwitter.h"
+#include "accounts/Account.h"
+#include "accounts/twitter/tomahawkoauthtwitter.h"
-#define MYNAME "SIPTWITTER"
-
-class SIPDLLEXPORT TwitterFactory : public SipPluginFactory
-{
- Q_OBJECT
- Q_INTERFACES( SipPluginFactory )
-
-public:
- TwitterFactory() {}
- virtual ~TwitterFactory() {}
-
- virtual QString prettyName() const { return "Twitter"; }
- virtual QString factoryId() const { return "siptwitter"; }
- virtual QIcon icon() const;
- virtual SipPlugin* createPlugin( const QString& pluginId = QString() );
-};
-
-class SIPDLLEXPORT TwitterPlugin : public SipPlugin
+class ACCOUNTDLLEXPORT TwitterSipPlugin : public SipPlugin
{
Q_OBJECT
public:
- TwitterPlugin( const QString& pluginId );
+ TwitterSipPlugin( Tomahawk::Accounts::Account *account );
- virtual ~TwitterPlugin() {}
+ virtual ~TwitterSipPlugin() {}
virtual bool isValid() const;
- virtual const QString name() const;
- virtual const QString accountName() const;
- virtual const QString friendlyName() const;
- virtual ConnectionState connectionState() const;
- virtual QIcon icon() const;
- virtual QWidget* configWidget();
+ virtual Tomahawk::Accounts::Account::ConnectionState connectionState() const;
+
+signals:
+ void stateChanged( Tomahawk::Accounts::Account::ConnectionState );
public slots:
- virtual bool connectPlugin( bool startup );
+ virtual void connectPlugin();
void disconnectPlugin();
- void checkSettings();
- void refreshProxy();
- void deletePlugin();
+ void configurationChanged();
void sendMsg( const QString& to, const QString& msg )
{
@@ -96,9 +75,10 @@ public slots:
Q_UNUSED( msg );
}
+ void checkSettings();
+
private slots:
- void configDialogAuthedSignalSlot( bool authed );
- void connectAuthVerifyReply( const QTweetUser &user );
+ void accountAuthenticated( const QWeakPointer< TomahawkOAuthTwitter > &twitterAuth, const QTweetUser &user );
void checkTimerFired();
void connectTimerFired();
void friendsTimelineStatuses( const QList< QTweetStatus > &statuses );
@@ -117,35 +97,20 @@ private slots:
void profilePicReply();
private:
- inline void syncConfig() { setTwitterCachedPeers( m_cachedPeers ); }
+ void syncConfig();
bool refreshTwitterAuth();
void parseGotTomahawk( const QRegExp ®ex, const QString &screenName, const QString &text );
- // handle per-plugin config
- QString twitterSavedDbid() const;
- void setTwitterSavedDbid( const QString& dbid );
- QString twitterScreenName() const;
- void setTwitterScreenName( const QString& screenName );
- QString twitterOAuthToken() const;
- void setTwitterOAuthToken( const QString& oauthtoken );
- QString twitterOAuthTokenSecret() const;
- void setTwitterOAuthTokenSecret( const QString& oauthtokensecret );
- qint64 twitterCachedFriendsSinceId() const;
- void setTwitterCachedFriendsSinceId( qint64 sinceid );
- qint64 twitterCachedMentionsSinceId() const;
- void setTwitterCachedMentionsSinceId( qint64 sinceid );
- qint64 twitterCachedDirectMessagesSinceId() const;
- void setTwitterCachedDirectMessagesSinceId( qint64 sinceid );
- QVariantHash twitterCachedPeers() const;
- void setTwitterCachedPeers( const QVariantHash &cachedPeers );
- QWeakPointer< TomahawkOAuthTwitter > m_twitterAuth;
+ QWeakPointer< TomahawkOAuthTwitter > m_cachedTwitterAuth;
+
QWeakPointer< QTweetFriendsTimeline > m_friendsTimeline;
QWeakPointer< QTweetMentions > m_mentions;
QWeakPointer< QTweetDirectMessages > m_directMessages;
QWeakPointer< QTweetDirectMessageNew > m_directMessageNew;
QWeakPointer< QTweetDirectMessageDestroy > m_directMessageDestroy;
- bool m_isAuthed;
+ QVariantHash m_configuration;
+
QTimer m_checkTimer;
QTimer m_connectTimer;
QTimer m_dmPollTimer;
@@ -155,12 +120,7 @@ private:
QVariantHash m_cachedPeers;
QHash< QString, QPixmap > m_cachedAvatars;
QSet m_keyCache;
- ConnectionState m_state;
-
- QWeakPointer m_configWidget;
-
- // for settings access
- friend class TwitterConfigWidget;
+ Tomahawk::Accounts::Account::ConnectionState m_state;
};
#endif
diff --git a/src/sip/twitter/tomahawkoauthtwitter.cpp b/src/accounts/twitter/tomahawkoauthtwitter.cpp
similarity index 96%
rename from src/sip/twitter/tomahawkoauthtwitter.cpp
rename to src/accounts/twitter/tomahawkoauthtwitter.cpp
index 35cd98a9e..b9b7e653d 100644
--- a/src/sip/twitter/tomahawkoauthtwitter.cpp
+++ b/src/accounts/twitter/tomahawkoauthtwitter.cpp
@@ -1,6 +1,6 @@
#include "tomahawkoauthtwitter.h"
-#include
+#include
#include "utils/logger.h"
diff --git a/src/accounts/twitter/tomahawkoauthtwitter.h b/src/accounts/twitter/tomahawkoauthtwitter.h
new file mode 100644
index 000000000..7cd243efe
--- /dev/null
+++ b/src/accounts/twitter/tomahawkoauthtwitter.h
@@ -0,0 +1,26 @@
+#ifndef TOMAHAWKOAUTHTWITTERACCOUNT
+#define TOMAHAWKOAUTHTWITTERACCOUNT
+
+#include "accounts/accountdllmacro.h"
+#include
+
+#include
+#include
+
+class ACCOUNTDLLEXPORT TomahawkOAuthTwitter : public OAuthTwitter
+{
+ Q_OBJECT
+
+public:
+ TomahawkOAuthTwitter( QNetworkAccessManager *nam = TomahawkUtils::nam() , QObject *parent = 0 );
+
+ ~TomahawkOAuthTwitter() {}
+
+protected:
+ virtual int authorizationWidget();
+
+private slots:
+ void error();
+};
+
+#endif
diff --git a/src/sip/twitter/twitter-icon.png b/src/accounts/twitter/twitter-icon.png
similarity index 100%
rename from src/sip/twitter/twitter-icon.png
rename to src/accounts/twitter/twitter-icon.png
diff --git a/src/accounts/twitter/twitteraccount.cpp b/src/accounts/twitter/twitteraccount.cpp
new file mode 100644
index 000000000..67bad5148
--- /dev/null
+++ b/src/accounts/twitter/twitteraccount.cpp
@@ -0,0 +1,186 @@
+/* === This file is part of Tomahawk Player - ===
+ *
+ * Copyright 2010-2011, Christian Muehlhaeuser
+ * Copyright 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 "twitteraccount.h"
+#include "twitterconfigwidget.h"
+#include "accounts/twitter/tomahawkoauthtwitter.h"
+
+#include "sip/SipPlugin.h"
+
+#include
+#include
+#include
+#include
+
+#include
+
+namespace Tomahawk
+{
+
+namespace Accounts
+{
+
+Account*
+TwitterAccountFactory::createAccount( const QString& accountId )
+{
+ return new TwitterAccount( accountId.isEmpty() ? Tomahawk::Accounts::generateId( factoryId() ) : accountId );
+}
+
+
+TwitterAccount::TwitterAccount( const QString &accountId )
+ : Account( accountId )
+ , m_isAuthenticated( false )
+{
+ setAccountServiceName( "Twitter" );
+ setTypes( AccountTypes( InfoType | SipType ) );
+
+ qDebug() << "Got cached peers:" << configuration() << configuration()[ "cachedpeers" ];
+
+ m_configWidget = QWeakPointer< TwitterConfigWidget >( new TwitterConfigWidget( this, 0 ) );
+ connect( m_configWidget.data(), SIGNAL( twitterAuthed( bool ) ), SLOT( configDialogAuthedSignalSlot( bool ) ) );
+
+ m_twitterAuth = QWeakPointer< TomahawkOAuthTwitter >( new TomahawkOAuthTwitter( TomahawkUtils::nam(), this ) );
+}
+
+
+TwitterAccount::~TwitterAccount()
+{
+
+}
+
+
+void
+TwitterAccount::configDialogAuthedSignalSlot( bool authed )
+{
+ tDebug() << Q_FUNC_INFO;
+ m_isAuthenticated = authed;
+ if ( !credentials()[ "username" ].toString().isEmpty() )
+ setAccountFriendlyName( QString( "@%1" ).arg( credentials()[ "username" ].toString() ) );
+ syncConfig();
+ emit configurationChanged();
+}
+
+
+Account::ConnectionState
+TwitterAccount::connectionState() const
+{
+ return m_twitterSipPlugin.data()->connectionState();
+}
+
+SipPlugin*
+TwitterAccount::sipPlugin()
+{
+ if ( m_twitterSipPlugin.isNull() )
+ {
+ qDebug() << "CHECKING:" << configuration() << configuration()[ "cachedpeers" ];
+ m_twitterSipPlugin = QWeakPointer< TwitterSipPlugin >( new TwitterSipPlugin( this ) );
+
+ connect( m_twitterSipPlugin.data(), SIGNAL( stateChanged( Tomahawk::Accounts::Account::ConnectionState ) ), this, SIGNAL( connectionStateChanged( Tomahawk::Accounts::Account::ConnectionState ) ) );
+ return m_twitterSipPlugin.data();
+ }
+ return m_twitterSipPlugin.data();
+}
+
+
+void
+TwitterAccount::authenticate()
+{
+ tDebug() << Q_FUNC_INFO << "credentials: " << credentials().keys();
+
+ if ( credentials()[ "oauthtoken" ].toString().isEmpty() || credentials()[ "oauthtokensecret" ].toString().isEmpty() )
+ {
+ qDebug() << "TwitterSipPlugin has empty Twitter credentials; not connecting";
+ return;
+ }
+
+ if ( refreshTwitterAuth() )
+ {
+ QTweetAccountVerifyCredentials *credVerifier = new QTweetAccountVerifyCredentials( m_twitterAuth.data(), this );
+ connect( credVerifier, SIGNAL( parsedUser( const QTweetUser & ) ), SLOT( connectAuthVerifyReply( const QTweetUser & ) ) );
+ credVerifier->verify();
+ }
+}
+
+
+void
+TwitterAccount::deauthenticate()
+{
+ if ( sipPlugin() )
+ sipPlugin()->disconnectPlugin();
+
+ m_isAuthenticated = false;
+ emit nowDeauthenticated();
+}
+
+
+
+bool
+TwitterAccount::refreshTwitterAuth()
+{
+ qDebug() << Q_FUNC_INFO << " begin";
+ if( !m_twitterAuth.isNull() )
+ delete m_twitterAuth.data();
+
+ Q_ASSERT( TomahawkUtils::nam() != 0 );
+ qDebug() << Q_FUNC_INFO << " with nam " << TomahawkUtils::nam();
+ m_twitterAuth = QWeakPointer< TomahawkOAuthTwitter >( new TomahawkOAuthTwitter( TomahawkUtils::nam(), this ) );
+
+ if( m_twitterAuth.isNull() )
+ return false;
+
+ m_twitterAuth.data()->setOAuthToken( credentials()[ "oauthtoken" ].toString().toLatin1() );
+ m_twitterAuth.data()->setOAuthTokenSecret( credentials()[ "oauthtokensecret" ].toString().toLatin1() );
+
+ return true;
+}
+
+
+void
+TwitterAccount::connectAuthVerifyReply( const QTweetUser &user )
+{
+ if ( user.id() == 0 )
+ {
+ qDebug() << "TwitterAccount could not authenticate to Twitter";
+ deauthenticate();
+ }
+ else
+ {
+ tDebug() << "TwitterAccount successfully authenticated to Twitter as user " << user.screenName();
+ QVariantHash config = configuration();
+ config[ "screenname" ] = user.screenName();
+ setConfiguration( config );
+ sync();
+
+ sipPlugin()->connectPlugin();
+
+ m_isAuthenticated = true;
+ emit nowAuthenticated( m_twitterAuth, user );
+ }
+}
+QPixmap
+TwitterAccount::icon() const {
+ return QPixmap( ":/twitter-icon.png" );
+}
+
+
+}
+
+}
+
+Q_EXPORT_PLUGIN2( Tomahawk::Accounts::AccountFactory, Tomahawk::Accounts::TwitterAccountFactory )
diff --git a/src/accounts/twitter/twitteraccount.h b/src/accounts/twitter/twitteraccount.h
new file mode 100644
index 000000000..a1a1c2629
--- /dev/null
+++ b/src/accounts/twitter/twitteraccount.h
@@ -0,0 +1,103 @@
+/* === This file is part of Tomahawk Player - ===
+ *
+ * Copyright 2010-2011, Christian Muehlhaeuser
+ * Copyright 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 TWITTERACCOUNT_H
+#define TWITTERACCOUNT_H
+
+#include "twitterconfigwidget.h"
+#include "tomahawkoauthtwitter.h"
+
+#include "sip/twittersip.h"
+#include "accounts/accountdllmacro.h"
+#include "accounts/Account.h"
+
+#define MYNAME "ACCOUNTTWITTER"
+
+namespace Tomahawk
+{
+
+namespace Accounts
+{
+
+class ACCOUNTDLLEXPORT TwitterAccountFactory : public AccountFactory
+{
+ Q_OBJECT
+ Q_INTERFACES( Tomahawk::Accounts::AccountFactory )
+
+public:
+ TwitterAccountFactory() {}
+ virtual ~TwitterAccountFactory() {}
+
+ QString prettyName() const { return "Twitter"; }
+ QString factoryId() const { return "twitteraccount"; }
+ QString description() const { return tr( "Connect to your Twitter followers." ); }
+ QPixmap icon() const { return QPixmap( ":/twitter-icon.png" ); }
+ AccountTypes types() const { return AccountTypes( SipType ); };
+ Account* createAccount( const QString& pluginId = QString() );
+};
+
+class ACCOUNTDLLEXPORT TwitterAccount : public Account
+{
+ Q_OBJECT
+
+public:
+ TwitterAccount( const QString &accountId );
+ virtual ~TwitterAccount();
+
+ QPixmap icon() const;
+
+ void authenticate();
+ void deauthenticate();
+ bool isAuthenticated() const { return m_isAuthenticated; }
+
+ ConnectionState connectionState() const;
+
+ Tomahawk::InfoSystem::InfoPlugin* infoPlugin() { return 0; }
+ SipPlugin* sipPlugin();
+
+ QWidget* configurationWidget() { return m_configWidget.data(); }
+ QWidget* aclWidget() { return 0; }
+
+ bool refreshTwitterAuth();
+ TomahawkOAuthTwitter* twitterAuth() const { return m_twitterAuth.data(); }
+
+signals:
+ void nowAuthenticated( const QWeakPointer< TomahawkOAuthTwitter >&, const QTweetUser &user );
+ void nowDeauthenticated();
+
+private slots:
+ void configDialogAuthedSignalSlot( bool authed );
+ void connectAuthVerifyReply( const QTweetUser &user );
+
+private:
+ QIcon m_icon;
+ bool m_isAuthenticated;
+ QWeakPointer< TomahawkOAuthTwitter > m_twitterAuth;
+ QWeakPointer< TwitterConfigWidget > m_configWidget;
+ QWeakPointer< TwitterSipPlugin > m_twitterSipPlugin;
+
+ // for settings access
+ friend class TwitterConfigWidget;
+};
+
+};
+
+};
+
+#endif
diff --git a/src/sip/twitter/twitterconfigwidget.cpp b/src/accounts/twitter/twitterconfigwidget.cpp
similarity index 61%
rename from src/sip/twitter/twitterconfigwidget.cpp
rename to src/accounts/twitter/twitterconfigwidget.cpp
index 535dcc8d1..1603b4b82 100644
--- a/src/sip/twitter/twitterconfigwidget.cpp
+++ b/src/accounts/twitter/twitterconfigwidget.cpp
@@ -17,7 +17,7 @@
*/
#include "twitterconfigwidget.h"
-#include "twitter.h"
+#include "twitteraccount.h"
#include "ui_twitterconfigwidget.h"
#include "tomahawksettings.h"
@@ -33,38 +33,47 @@
#include "utils/logger.h"
-
-TwitterConfigWidget::TwitterConfigWidget( TwitterPlugin* plugin, QWidget *parent ) :
- QWidget( parent ),
- ui( new Ui::TwitterConfigWidget ),
- m_plugin( plugin )
+namespace Tomahawk
{
- ui->setupUi( this );
- connect( ui->twitterAuthenticateButton, SIGNAL( pressed() ),
+namespace Accounts
+{
+
+TwitterConfigWidget::TwitterConfigWidget( TwitterAccount* account, QWidget *parent ) :
+ QWidget( parent ),
+ m_ui( new Ui::TwitterConfigWidget ),
+ m_account( account )
+{
+ m_ui->setupUi( this );
+
+ connect( m_ui->twitterAuthenticateButton, SIGNAL( pressed() ),
this, SLOT( authDeauthTwitter() ) );
- connect( ui->twitterTweetGotTomahawkButton, SIGNAL( pressed() ),
+ connect( m_ui->twitterTweetGotTomahawkButton, SIGNAL( pressed() ),
this, SLOT( startPostGotTomahawkStatus() ) );
- connect( ui->twitterTweetComboBox, SIGNAL( currentIndexChanged( int ) ),
+ connect( m_ui->twitterTweetComboBox, SIGNAL( currentIndexChanged( int ) ),
this, SLOT( tweetComboBoxIndexChanged( int ) ) );
- ui->twitterTweetComboBox->setCurrentIndex( 0 );
- ui->twitterTweetGotTomahawkButton->setText( tr( "Tweet!" ) );
+ m_ui->twitterTweetComboBox->setCurrentIndex( 0 );
+ m_ui->twitterTweetGotTomahawkButton->setText( tr( "Tweet!" ) );
- if ( m_plugin->twitterOAuthToken().isEmpty() || m_plugin->twitterOAuthTokenSecret().isEmpty() || m_plugin->twitterScreenName().isEmpty() )
+ QVariantHash credentials = m_account->credentials();
+
+ if ( credentials[ "oauthtoken" ].toString().isEmpty() ||
+ credentials[ "oauthtokensecret" ].toString().isEmpty() ||
+ credentials[ "username" ].toString().isEmpty() )
{
- ui->twitterStatusLabel->setText( tr( "Status: No saved credentials" ) );
- ui->twitterAuthenticateButton->setText( tr( "Authenticate" ) );
- ui->twitterSyncGroupBox->setVisible( false );
+ m_ui->twitterStatusLabel->setText( tr( "Status: No saved credentials" ) );
+ m_ui->twitterAuthenticateButton->setText( tr( "Authenticate" ) );
+ m_ui->twitterSyncGroupBox->setVisible( false );
emit twitterAuthed( false );
}
else
{
- ui->twitterStatusLabel->setText( tr( "Status: Credentials saved for %1" ).arg( m_plugin->twitterScreenName() ) );
- ui->twitterAuthenticateButton->setText( tr( "De-authenticate" ) );
- ui->twitterSyncGroupBox->setVisible( true );
- ui->twitterUserTweetLineEdit->setVisible( false );
+ m_ui->twitterStatusLabel->setText( tr( "Status: Credentials saved for %1" ).arg( m_account->credentials()[ "username" ].toString() ) );
+ m_ui->twitterAuthenticateButton->setText( tr( "De-authenticate" ) );
+ m_ui->twitterSyncGroupBox->setVisible( true );
+ m_ui->twitterUserTweetLineEdit->setVisible( false );
emit twitterAuthed( true );
}
@@ -73,13 +82,13 @@ TwitterConfigWidget::TwitterConfigWidget( TwitterPlugin* plugin, QWidget *parent
TwitterConfigWidget::~TwitterConfigWidget()
{
- delete ui;
+ delete m_ui;
}
void
TwitterConfigWidget::authDeauthTwitter()
{
- if ( ui->twitterAuthenticateButton->text() == tr( "Authenticate" ) ) //FIXME: don't rely on UI strings here!
+ if ( m_ui->twitterAuthenticateButton->text() == tr( "Authenticate" ) ) //FIXME: don't rely on UI strings here!
authenticateTwitter();
else
deauthenticateTwitter();
@@ -92,8 +101,10 @@ TwitterConfigWidget::authenticateTwitter()
TomahawkOAuthTwitter *twitAuth = new TomahawkOAuthTwitter( TomahawkUtils::nam(), this );
twitAuth->authorizePin();
- m_plugin->setTwitterOAuthToken( twitAuth->oauthToken() );
- m_plugin->setTwitterOAuthTokenSecret( twitAuth->oauthTokenSecret() );
+ QVariantHash credentials = m_account->credentials();
+ credentials[ "oauthtoken" ] = twitAuth->oauthToken();
+ credentials[ "oauthtokensecret" ] = twitAuth->oauthTokenSecret();
+ m_account->setCredentials( credentials );
QTweetAccountVerifyCredentials *credVerifier = new QTweetAccountVerifyCredentials( twitAuth, this );
connect( credVerifier, SIGNAL( parsedUser( const QTweetUser & ) ), SLOT( authenticateVerifyReply( const QTweetUser & ) ) );
@@ -112,18 +123,21 @@ TwitterConfigWidget::authenticateVerifyReply( const QTweetUser &user )
return;
}
- m_plugin->setTwitterScreenName( user.screenName() );
- m_plugin->setTwitterCachedFriendsSinceId( 0 );
- m_plugin->setTwitterCachedMentionsSinceId( 0 );
+ QVariantHash credentials = m_account->credentials();
+ credentials[ "username" ] = user.screenName();
+ m_account->setCredentials( credentials );
- ui->twitterStatusLabel->setText( tr( "Status: Credentials saved for %1" ).arg( m_plugin->twitterScreenName() ) );
- ui->twitterAuthenticateButton->setText( tr( "De-authenticate" ) );
- ui->twitterSyncGroupBox->setVisible( true );
- ui->twitterTweetComboBox->setCurrentIndex( 0 );
- ui->twitterUserTweetLineEdit->setVisible( false );
- ui->twitterTweetGotTomahawkButton->setText( tr( "Tweet!" ) );
+ QVariantHash configuration = m_account->configuration();
+ configuration[ "sipcachedfriendssinceid" ] = 0;
+ configuration[ "sipcachedmentionssinceid" ] = 0;
+ m_account->setConfiguration( configuration );
- m_plugin->connectPlugin( false );
+ m_ui->twitterStatusLabel->setText( tr( "Status: Credentials saved for %1" ).arg( user.screenName() ) );
+ m_ui->twitterAuthenticateButton->setText( tr( "De-authenticate" ) );
+ m_ui->twitterSyncGroupBox->setVisible( true );
+ m_ui->twitterTweetComboBox->setCurrentIndex( 0 );
+ m_ui->twitterUserTweetLineEdit->setVisible( false );
+ m_ui->twitterTweetGotTomahawkButton->setText( tr( "Tweet!" ) );
emit twitterAuthed( true );
emit sizeHintChanged();
@@ -134,7 +148,7 @@ TwitterConfigWidget::authenticateVerifyError( QTweetNetBase::ErrorCode code, con
{
qDebug() << Q_FUNC_INFO;
qDebug() << "Error validating credentials, error code is " << code << ", error message is " << errorMsg;
- ui->twitterStatusLabel->setText(tr("Status: Error validating credentials"));
+ m_ui->twitterStatusLabel->setText(tr("Status: Error validating credentials"));
emit twitterAuthed( false );
return;
}
@@ -143,13 +157,15 @@ void
TwitterConfigWidget::deauthenticateTwitter()
{
qDebug() << Q_FUNC_INFO;
- m_plugin->setTwitterOAuthToken( QString() );
- m_plugin->setTwitterOAuthTokenSecret( QString() );
- m_plugin->setTwitterScreenName( QString() );
+ QVariantHash credentials = m_account->credentials();
+ credentials[ "oauthtoken" ] = QString();
+ credentials[ "oauthtokensecret" ] = QString();
+ credentials[ "username" ] = QString();
+ m_account->setCredentials( credentials );
- ui->twitterStatusLabel->setText(tr("Status: No saved credentials"));
- ui->twitterAuthenticateButton->setText( tr( "Authenticate" ) );
- ui->twitterSyncGroupBox->setVisible( false );
+ m_ui->twitterStatusLabel->setText(tr("Status: No saved credentials"));
+ m_ui->twitterAuthenticateButton->setText( tr( "Authenticate" ) );
+ m_ui->twitterSyncGroupBox->setVisible( false );
emit twitterAuthed( false );
emit sizeHintChanged();
@@ -159,41 +175,45 @@ void
TwitterConfigWidget::tweetComboBoxIndexChanged( int index )
{
Q_UNUSED( index );
- if ( ui->twitterTweetComboBox->currentText() == tr( "Global Tweet" ) ) //FIXME: use data!
- ui->twitterUserTweetLineEdit->setVisible( false );
+ if ( m_ui->twitterTweetComboBox->currentText() == tr( "Global Tweet" ) ) //FIXME: use data!
+ m_ui->twitterUserTweetLineEdit->setVisible( false );
else
- ui->twitterUserTweetLineEdit->setVisible( true );
+ m_ui->twitterUserTweetLineEdit->setVisible( true );
- if ( ui->twitterTweetComboBox->currentText() == tr( "Direct Message" ) ) //FIXME: use data!
- ui->twitterTweetGotTomahawkButton->setText( tr( "Send Message!" ) );
- else if ( ui->twitterTweetComboBox->currentText() == tr( "@Mention" ) )
- ui->twitterTweetGotTomahawkButton->setText( tr( "Send Mention!" ) );
+ if ( m_ui->twitterTweetComboBox->currentText() == tr( "Direct Message" ) ) //FIXME: use data!
+ m_ui->twitterTweetGotTomahawkButton->setText( tr( "Send Message!" ) );
+ else if ( m_ui->twitterTweetComboBox->currentText() == tr( "@Mention" ) )
+ m_ui->twitterTweetGotTomahawkButton->setText( tr( "Send Mention!" ) );
else
- ui->twitterTweetGotTomahawkButton->setText( tr( "Tweet!" ) );
+ m_ui->twitterTweetGotTomahawkButton->setText( tr( "Tweet!" ) );
}
void
TwitterConfigWidget::startPostGotTomahawkStatus()
{
qDebug() << Q_FUNC_INFO;
- m_postGTtype = ui->twitterTweetComboBox->currentText();
+ m_postGTtype = m_ui->twitterTweetComboBox->currentText();
- if ( m_postGTtype != "Global Tweet" && ( ui->twitterUserTweetLineEdit->text().isEmpty() || ui->twitterUserTweetLineEdit->text() == "@" ) )
+ if ( m_postGTtype != "Global Tweet" && ( m_ui->twitterUserTweetLineEdit->text().isEmpty() || m_ui->twitterUserTweetLineEdit->text() == "@" ) )
{
QMessageBox::critical( this, tr("Tweetin' Error"), tr("You must enter a user name for this type of tweet.") );
return;
}
qDebug() << "Posting Got Tomahawk status";
- if ( m_plugin->twitterOAuthToken().isEmpty() || m_plugin->twitterOAuthTokenSecret().isEmpty() || m_plugin->twitterScreenName().isEmpty() )
+ QVariantHash credentials = m_account->credentials();
+
+ if ( credentials[ "oauthtoken" ].toString().isEmpty() ||
+ credentials[ "oauthtokensecret" ].toString().isEmpty() ||
+ credentials[ "username" ].toString().isEmpty() )
{
QMessageBox::critical( this, tr("Tweetin' Error"), tr("Your saved credentials could not be loaded.\nYou may wish to try re-authenticating.") );
emit twitterAuthed( false );
return;
}
TomahawkOAuthTwitter *twitAuth = new TomahawkOAuthTwitter( TomahawkUtils::nam(), this );
- twitAuth->setOAuthToken( m_plugin->twitterOAuthToken().toLatin1() );
- twitAuth->setOAuthTokenSecret( m_plugin->twitterOAuthTokenSecret().toLatin1() );
+ twitAuth->setOAuthToken( credentials[ "oauthtoken" ].toString().toLatin1() );
+ twitAuth->setOAuthTokenSecret( credentials[ "oauthtokensecret" ].toString().toLatin1() );
QTweetAccountVerifyCredentials *credVerifier = new QTweetAccountVerifyCredentials( twitAuth, this );
connect( credVerifier, SIGNAL( parsedUser(const QTweetUser &) ), SLOT( postGotTomahawkStatusAuthVerifyReply(const QTweetUser &) ) );
credVerifier->verify();
@@ -209,10 +229,10 @@ TwitterConfigWidget::postGotTomahawkStatusAuthVerifyReply( const QTweetUser &use
emit twitterAuthed( false );
return;
}
- m_plugin->setTwitterScreenName( user.screenName() );
TomahawkOAuthTwitter *twitAuth = new TomahawkOAuthTwitter( TomahawkUtils::nam(), this );
- twitAuth->setOAuthToken( m_plugin->twitterOAuthToken().toLatin1() );
- twitAuth->setOAuthTokenSecret( m_plugin->twitterOAuthTokenSecret().toLatin1() );
+ QVariantHash credentials = m_account->credentials();
+ twitAuth->setOAuthToken( credentials[ "oauthtoken" ].toString().toLatin1() );
+ twitAuth->setOAuthTokenSecret( credentials[ "oauthtokensecret" ].toString().toLatin1() );
if ( m_postGTtype != "Direct Message" )
{
QTweetStatusUpdate *statUpdate = new QTweetStatusUpdate( twitAuth, this );
@@ -222,7 +242,7 @@ TwitterConfigWidget::postGotTomahawkStatusAuthVerifyReply( const QTweetUser &use
QString message = QString( "Got Tomahawk? {" ) + Database::instance()->dbid() + QString( "} (" ) + uuid.mid( 1, 8 ) + QString( ")" ) + QString( " http://gettomahawk.com" );
if ( m_postGTtype == "@Mention" )
{
- QString user = ui->twitterUserTweetLineEdit->text();
+ QString user = m_ui->twitterUserTweetLineEdit->text();
if ( user.startsWith( "@" ) )
user.remove( 0, 1 );
message = QString( "@" ) + user + QString( " " ) + message;
@@ -236,7 +256,7 @@ TwitterConfigWidget::postGotTomahawkStatusAuthVerifyReply( const QTweetUser &use
connect( statUpdate, SIGNAL( error(QTweetNetBase::ErrorCode, const QString&) ), SLOT( postGotTomahawkStatusUpdateError(QTweetNetBase::ErrorCode, const QString &) ) );
QString uuid = QUuid::createUuid();
QString message = QString( "Got Tomahawk? {" ) + Database::instance()->dbid() + QString( "} (" ) + uuid.mid( 1, 8 ) + QString( ")" ) + QString( " http://gettomahawk.com" );
- QString user = ui->twitterUserTweetLineEdit->text();
+ QString user = m_ui->twitterUserTweetLineEdit->text();
if ( user.startsWith( "@" ) )
user.remove( 0, 1 );
statUpdate->post( user, message );
@@ -268,3 +288,7 @@ TwitterConfigWidget::postGotTomahawkStatusUpdateError( QTweetNetBase::ErrorCode
qDebug() << "Error posting Got Tomahawk message, error code is " << code << ", error message is " << errorMsg;
QMessageBox::critical( this, tr("Tweetin' Error"), tr("There was an error posting your status -- sorry!") );
}
+
+}
+
+}
\ No newline at end of file
diff --git a/src/sip/twitter/twitterconfigwidget.h b/src/accounts/twitter/twitterconfigwidget.h
similarity index 80%
rename from src/sip/twitter/twitterconfigwidget.h
rename to src/accounts/twitter/twitterconfigwidget.h
index d06c08737..3b8048146 100644
--- a/src/sip/twitter/twitterconfigwidget.h
+++ b/src/accounts/twitter/twitterconfigwidget.h
@@ -16,10 +16,10 @@
* along with Tomahawk. If not, see .
*/
-#ifndef TWITTERCONFIGWIDGET_H
-#define TWITTERCONFIGWIDGET_H
+#ifndef TWITTERACCOUNTCONFIGWIDGET_H
+#define TWITTERACCOUNTCONFIGWIDGET_H
-#include "sip/SipPlugin.h"
+#include "accounts/accountdllmacro.h"
#include
#include
@@ -28,24 +28,33 @@
#include
-class TwitterPlugin;
-
-namespace Ui {
+namespace Ui
+{
class TwitterConfigWidget;
}
-class TwitterConfigWidget : public QWidget
+namespace Tomahawk
+{
+
+namespace Accounts
+{
+
+class TwitterAccount;
+
+
+class ACCOUNTDLLEXPORT TwitterConfigWidget : public QWidget
{
Q_OBJECT
public:
- explicit TwitterConfigWidget( TwitterPlugin* plugin = 0, QWidget *parent = 0 );
- ~TwitterConfigWidget();
+ explicit TwitterConfigWidget( TwitterAccount* account = 0, QWidget *parent = 0 );
+ virtual ~TwitterConfigWidget();
signals:
void twitterAuthed( bool authed );
void sizeHintChanged();
+
private slots:
void authDeauthTwitter();
void startPostGotTomahawkStatus();
@@ -61,9 +70,13 @@ private:
void authenticateTwitter();
void deauthenticateTwitter();
- Ui::TwitterConfigWidget *ui;
- TwitterPlugin *m_plugin;
+ Ui::TwitterConfigWidget *m_ui;
+ TwitterAccount *m_account;
QString m_postGTtype;
};
+}
+
+}
+
#endif // TWITTERCONFIGWIDGET_H
diff --git a/src/sip/twitter/twitterconfigwidget.ui b/src/accounts/twitter/twitterconfigwidget.ui
similarity index 100%
rename from src/sip/twitter/twitterconfigwidget.ui
rename to src/accounts/twitter/twitterconfigwidget.ui
diff --git a/src/accounts/xmpp/CMakeLists.txt b/src/accounts/xmpp/CMakeLists.txt
new file mode 100644
index 000000000..ff1f5da2a
--- /dev/null
+++ b/src/accounts/xmpp/CMakeLists.txt
@@ -0,0 +1,64 @@
+project( tomahawk )
+
+include( ${QT_USE_FILE} )
+add_definitions( ${QT_DEFINITIONS} )
+add_definitions( -DQT_PLUGIN )
+add_definitions( -DQT_SHARED )
+add_definitions( -DACCOUNTDLLEXPORT_PRO )
+
+set( xmppAccountSources
+ xmppaccount.cpp
+ xmppconfigwidget.cpp
+ sip/xmppsip.cpp
+ sip/tomahawkxmppmessage.cpp
+ sip/tomahawkxmppmessagefactory.cpp
+ sip/avatarmanager.cpp
+ sip/xmlconsole.cpp
+)
+
+set( xmppAccountHeaders
+ xmppaccount.h
+ xmppconfigwidget.h
+ sip/xmppsip.h
+ sip/avatarmanager.h
+ sip/xmlconsole.h
+)
+
+set( xmppAccountUI
+ xmppconfigwidget.ui
+ sip/xmlconsole.ui
+)
+
+include_directories( . ${CMAKE_CURRENT_BINARY_DIR} ..
+ ${QT_INCLUDE_DIR}
+ ${LIBJREEN_INCLUDE_DIR}
+)
+
+qt4_wrap_cpp( xmppAccountMoc ${xmppAccountHeaders} )
+qt4_wrap_ui( xmppAccountUI_H ${xmppAccountUI} )
+qt4_add_resources( RC_SRCS "resources.qrc" )
+add_library( tomahawk_account_xmpp MODULE ${xmppAccountUI_H} ${xmppAccountSources} ${xmppAccountMoc} ${RC_SRCS} )
+
+IF( WIN32 )
+SET( OS_SPECIFIC_LINK_LIBRARIES
+ ${OS_SPECIFIC_LINK_LIBRARIES}
+ "winmm.dll"
+ "iphlpapi.a"
+)
+ENDIF( WIN32 )
+
+target_link_libraries( tomahawk_account_xmpp
+ ${TOMAHAWK_LIBRARIES}
+ ${LIBJREEN_LIBRARY}
+ ${QT_LIBRARIES}
+ ${OS_SPECIFIC_LINK_LIBRARIES}
+)
+
+IF( APPLE )
+# SET( CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS} "-undefined dynamic_lookup" )
+ENDIF( APPLE )
+
+install( TARGETS tomahawk_account_xmpp DESTINATION ${CMAKE_INSTALL_LIBDIR} )
+
+add_subdirectory(googlewrapper)
+
diff --git a/src/accounts/xmpp/googlewrapper/CMakeLists.txt b/src/accounts/xmpp/googlewrapper/CMakeLists.txt
new file mode 100644
index 000000000..a2ce9560b
--- /dev/null
+++ b/src/accounts/xmpp/googlewrapper/CMakeLists.txt
@@ -0,0 +1,37 @@
+
+# fake google plugin
+
+set( googleHeaders
+ ../xmppaccount.h
+ ../xmppconfigwidget.h
+ ../sip/xmppsip.h
+ ../sip/avatarmanager.h
+ ../sip/xmlconsole.h
+ googlewrapper.h )
+
+set( googleSources
+ ../xmppaccount.cpp
+ ../xmppconfigwidget.cpp
+ ../sip/xmppsip.cpp
+ ../sip/tomahawkxmppmessage.cpp
+ ../sip/tomahawkxmppmessagefactory.cpp
+ ../sip/avatarmanager.cpp
+ ../sip/xmlconsole.cpp
+
+ googlewrapper.cpp )
+
+add_definitions(-DGOOGLE_WRAPPER)
+
+qt4_add_resources( RCX_SRCS "resources.qrc" )
+
+qt4_wrap_cpp( googleMoc ${googleHeaders} )
+add_library( tomahawk_account_google MODULE ${googleSources} ${googleMoc} ${googleMoc} ${RCX_SRCS} )
+
+target_link_libraries( tomahawk_account_google
+ ${QT_LIBRARIES}
+ ${LIBJREEN_LIBRARY}
+ ${OS_SPECIFIC_LINK_LIBRARIES}
+ tomahawklib
+)
+
+install( TARGETS tomahawk_account_google DESTINATION ${CMAKE_INSTALL_LIBDIR} )
diff --git a/src/sip/jabber/googlewrapper/gmail-logo.png b/src/accounts/xmpp/googlewrapper/gmail-logo.png
similarity index 100%
rename from src/sip/jabber/googlewrapper/gmail-logo.png
rename to src/accounts/xmpp/googlewrapper/gmail-logo.png
diff --git a/src/accounts/xmpp/googlewrapper/googlewrapper.cpp b/src/accounts/xmpp/googlewrapper/googlewrapper.cpp
new file mode 100644
index 000000000..858565aba
--- /dev/null
+++ b/src/accounts/xmpp/googlewrapper/googlewrapper.cpp
@@ -0,0 +1,122 @@
+/*
+
+ 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 "googlewrapper.h"
+#include "xmppconfigwidget.h"
+#include "ui_xmppconfigwidget.h"
+
+#include "utils/tomahawkutilsgui.h"
+
+#include
+#include
+
+using namespace Tomahawk;
+using namespace Accounts;
+
+Account*
+GoogleWrapperFactory::createAccount( const QString& pluginId )
+{
+ return new GoogleWrapper( pluginId.isEmpty() ? generateId( factoryId() ) : pluginId );
+}
+
+
+QPixmap
+GoogleWrapperFactory::icon() const
+{
+ return QPixmap( ":/gmail-logo.png" );
+}
+
+GoogleWrapperSip::GoogleWrapperSip( Account* account )
+ : XmppSipPlugin( account )
+{
+
+}
+
+GoogleWrapperSip::~GoogleWrapperSip()
+{
+}
+
+
+void
+GoogleWrapperSip::showAddFriendDialog()
+{
+ bool ok;
+ QString id = QInputDialog::getText( TomahawkUtils::tomahawkWindow(), tr( "Add Friend" ),
+ tr( "Enter Google Address:" ), QLineEdit::Normal, "", &ok );
+ if ( !ok )
+ return;
+
+ qDebug() << "Attempting to add google contact to roster:" << id;
+ addContact( id );
+}
+
+
+QString
+GoogleWrapperSip::defaultSuffix() const
+{
+ return "@gmail.com";
+}
+
+
+GoogleWrapper::GoogleWrapper ( const QString& pluginID )
+ : XmppAccount ( pluginID )
+{
+ XmppConfigWidget* config = static_cast< XmppConfigWidget* >( m_configWidget.data() );
+ config->m_ui->headerLabel->setText( tr( "Configure this Google Account" ) );
+ config->m_ui->emailLabel->setText( tr( "Google Address" ) );
+ config->m_ui->xmppBlurb->setText( tr( "Enter your Google login to connect with your friends using Tomahawk!" ) );
+ config->m_ui->xmppUsername->setPlaceholderText( tr( "username@gmail.com" ) );
+ config->m_ui->logoLabel->setPixmap( QPixmap( ":/gmail-logo.png" ) );
+ config->m_ui->xmppServer->setText( "talk.google.com" );
+ config->m_ui->xmppPort->setValue( 5222 );
+ config->m_ui->groupBoxXmppAdvanced->hide();
+}
+
+GoogleWrapper::~GoogleWrapper()
+{
+ delete m_sipPlugin.data();
+}
+
+
+QPixmap
+GoogleWrapper::icon() const
+{
+ return QPixmap( ":/gmail-logo.png" );
+}
+
+
+SipPlugin*
+GoogleWrapper::sipPlugin()
+{
+ if ( m_xmppSipPlugin.isNull() )
+ {
+ m_xmppSipPlugin = QWeakPointer< XmppSipPlugin >( new GoogleWrapperSip( const_cast< GoogleWrapper* >( this ) ) );
+
+ connect( m_xmppSipPlugin.data(), SIGNAL( stateChanged( Tomahawk::Accounts::Account::ConnectionState ) ), this, SIGNAL( connectionStateChanged( Tomahawk::Accounts::Account::ConnectionState ) ) );
+ connect( m_xmppSipPlugin.data(), SIGNAL( error( int, QString ) ), this, SIGNAL( error( int, QString ) ) );
+
+ return m_xmppSipPlugin.data();
+ }
+ return m_xmppSipPlugin.data();
+}
+
+
+#ifdef GOOGLE_WRAPPER
+Q_EXPORT_PLUGIN2( Tomahawk::Accounts::AccountFactory, Tomahawk::Accounts::GoogleWrapperFactory )
+#endif
diff --git a/src/sip/jabber/googlewrapper/googlewrapper.h b/src/accounts/xmpp/googlewrapper/googlewrapper.h
similarity index 50%
rename from src/sip/jabber/googlewrapper/googlewrapper.h
rename to src/accounts/xmpp/googlewrapper/googlewrapper.h
index f34238c6a..833cf3be2 100644
--- a/src/sip/jabber/googlewrapper/googlewrapper.h
+++ b/src/accounts/xmpp/googlewrapper/googlewrapper.h
@@ -19,39 +19,63 @@
#ifndef GOOGLEWRAPPER_H
#define GOOGLEWRAPPER_H
-#include "sip/jabber/jabber.h"
+#include "xmppaccount.h"
-class SIPDLLEXPORT GoogleWrapperFactory : public SipPluginFactory
+namespace Tomahawk
+{
+
+namespace Accounts
+{
+
+class ACCOUNTDLLEXPORT GoogleWrapperFactory : public XmppAccountFactory
{
Q_OBJECT
- Q_INTERFACES( SipPluginFactory )
+ Q_INTERFACES( Tomahawk::Accounts::AccountFactory )
public:
GoogleWrapperFactory() {}
virtual ~GoogleWrapperFactory() {}
virtual QString prettyName() const { return "Google"; }
- virtual QString factoryId() const { return "sipgoogle"; }
- virtual QIcon icon() const;
- virtual SipPlugin* createPlugin( const QString& pluginId );
+ virtual QString factoryId() const { return "googleaccount"; }
+ QString description() const { return tr( "Connect to GChat to find your friends" ); }
+ virtual QPixmap icon() const;
+ virtual Account* createAccount( const QString& pluginId );
};
-class SIPDLLEXPORT GoogleWrapper : public JabberPlugin
+class ACCOUNTDLLEXPORT GoogleWrapperSip : public XmppSipPlugin
{
Q_OBJECT
public:
- GoogleWrapper( const QString& pluginID );
- virtual ~GoogleWrapper() {}
-
- virtual const QString name() const { return QString( "Google" ); }
- virtual const QString friendlyName() const { return "Google"; }
- virtual QIcon icon() const;
-
-protected:
- QString defaultSuffix() const;
+ GoogleWrapperSip( Tomahawk::Accounts::Account* account );
+ virtual ~GoogleWrapperSip();
public slots:
void showAddFriendDialog();
+
+protected:
+ QString defaultSuffix() const;
};
+class ACCOUNTDLLEXPORT GoogleWrapper : public XmppAccount
+{
+ Q_OBJECT
+public:
+ GoogleWrapper( const QString& pluginID );
+ virtual ~GoogleWrapper();
+
+ virtual const QString name() const { return QString( "Google" ); }
+ virtual const QString friendlyName() const { return "Google"; }
+ virtual QPixmap icon() const;
+
+ virtual SipPlugin* sipPlugin();
+
+private:
+ QWeakPointer< GoogleWrapperSip > m_sipPlugin;
+};
+
+}
+
+}
+
#endif // GOOGLEWRAPPER_H
diff --git a/src/sip/jabber/googlewrapper/resources.qrc b/src/accounts/xmpp/googlewrapper/resources.qrc
similarity index 100%
rename from src/sip/jabber/googlewrapper/resources.qrc
rename to src/accounts/xmpp/googlewrapper/resources.qrc
diff --git a/src/sip/jabber/resources.qrc b/src/accounts/xmpp/resources.qrc
similarity index 69%
rename from src/sip/jabber/resources.qrc
rename to src/accounts/xmpp/resources.qrc
index 9700ac51f..7240db9d3 100644
--- a/src/sip/jabber/resources.qrc
+++ b/src/accounts/xmpp/resources.qrc
@@ -1,5 +1,5 @@
-jabber-icon.png
+xmpp-icon.png
diff --git a/src/sip/jabber/avatarmanager.cpp b/src/accounts/xmpp/sip/avatarmanager.cpp
similarity index 100%
rename from src/sip/jabber/avatarmanager.cpp
rename to src/accounts/xmpp/sip/avatarmanager.cpp
diff --git a/src/sip/jabber/avatarmanager.h b/src/accounts/xmpp/sip/avatarmanager.h
similarity index 92%
rename from src/sip/jabber/avatarmanager.h
rename to src/accounts/xmpp/sip/avatarmanager.h
index ea755d76e..c16711453 100644
--- a/src/sip/jabber/avatarmanager.h
+++ b/src/accounts/xmpp/sip/avatarmanager.h
@@ -21,12 +21,12 @@
#include
-#include
-#include
+#include
+#include
-#include "../sipdllmacro.h"
+#include "accounts/accountdllmacro.h"
-class SIPDLLEXPORT AvatarManager : public QObject
+class ACCOUNTDLLEXPORT AvatarManager : public QObject
{
Q_OBJECT
diff --git a/src/sip/jabber/tomahawksipmessage.cpp b/src/accounts/xmpp/sip/tomahawkxmppmessage.cpp
similarity index 66%
rename from src/sip/jabber/tomahawksipmessage.cpp
rename to src/accounts/xmpp/sip/tomahawkxmppmessage.cpp
index 68ecfea79..1b0cf0804 100644
--- a/src/sip/jabber/tomahawksipmessage.cpp
+++ b/src/accounts/xmpp/sip/tomahawkxmppmessage.cpp
@@ -16,12 +16,12 @@
* along with Tomahawk. If not, see .
*/
-#include "tomahawksipmessage.h"
+#include "tomahawkxmppmessage.h"
#include "utils/logger.h"
-class TomahawkSipMessagePrivate
+class TomahawkXmppMessagePrivate
{
public:
QString ip;
@@ -31,9 +31,9 @@ public:
bool visible;
};
-TomahawkSipMessage::TomahawkSipMessage(const QString &ip, unsigned int port, const QString &uniqname, const QString &key) : d_ptr(new TomahawkSipMessagePrivate)
+TomahawkXmppMessage::TomahawkXmppMessage(const QString &ip, unsigned int port, const QString &uniqname, const QString &key) : d_ptr(new TomahawkXmppMessagePrivate)
{
- Q_D(TomahawkSipMessage);
+ Q_D(TomahawkXmppMessage);
d->ip = ip;
d->port = port;
d->uniqname = uniqname;
@@ -41,39 +41,39 @@ TomahawkSipMessage::TomahawkSipMessage(const QString &ip, unsigned int port, con
d->visible = true;
}
-TomahawkSipMessage::TomahawkSipMessage() : d_ptr(new TomahawkSipMessagePrivate)
+TomahawkXmppMessage::TomahawkXmppMessage() : d_ptr(new TomahawkXmppMessagePrivate)
{
- Q_D(TomahawkSipMessage);
+ Q_D(TomahawkXmppMessage);
d->visible = false;
d->port = -1;
}
-TomahawkSipMessage::~TomahawkSipMessage()
+TomahawkXmppMessage::~TomahawkXmppMessage()
{
}
-const QString TomahawkSipMessage::ip() const
+const QString TomahawkXmppMessage::ip() const
{
return d_func()->ip;
}
-unsigned int TomahawkSipMessage::port() const
+unsigned int TomahawkXmppMessage::port() const
{
return d_func()->port;
}
-const QString TomahawkSipMessage::uniqname() const
+const QString TomahawkXmppMessage::uniqname() const
{
return d_func()->uniqname;
}
-const QString TomahawkSipMessage::key() const
+const QString TomahawkXmppMessage::key() const
{
return d_func()->key;
}
-bool TomahawkSipMessage::visible() const
+bool TomahawkXmppMessage::visible() const
{
return d_func()->visible;
}
diff --git a/src/sip/jabber/tomahawksipmessage.h b/src/accounts/xmpp/sip/tomahawkxmppmessage.h
similarity index 74%
rename from src/sip/jabber/tomahawksipmessage.h
rename to src/accounts/xmpp/sip/tomahawkxmppmessage.h
index 0dbdb0ad0..8661c30bd 100644
--- a/src/sip/jabber/tomahawksipmessage.h
+++ b/src/accounts/xmpp/sip/tomahawkxmppmessage.h
@@ -23,20 +23,20 @@
#define TOMAHAWK_SIP_MESSAGE_NS QLatin1String("http://www.tomhawk-player.org/sip/transports")
-#include "../sipdllmacro.h"
+#include "accounts/accountdllmacro.h"
-class TomahawkSipMessagePrivate;
-class SIPDLLEXPORT TomahawkSipMessage : public Jreen::Payload
+class TomahawkXmppMessagePrivate;
+class ACCOUNTDLLEXPORT TomahawkXmppMessage : public Jreen::Payload
{
- J_PAYLOAD(TomahawkSipMessage)
- Q_DECLARE_PRIVATE(TomahawkSipMessage)
+ J_PAYLOAD(TomahawkXmppMessage)
+ Q_DECLARE_PRIVATE(TomahawkXmppMessage)
public:
// sets visible to true
- TomahawkSipMessage(const QString &ip, unsigned int port, const QString &uniqname, const QString &key);
+ TomahawkXmppMessage(const QString &ip, unsigned int port, const QString &uniqname, const QString &key);
// sets visible to false as we dont have any extra information
- TomahawkSipMessage();
- ~TomahawkSipMessage();
+ TomahawkXmppMessage();
+ ~TomahawkXmppMessage();
const QString ip() const;
unsigned int port() const;
@@ -44,7 +44,7 @@ class SIPDLLEXPORT TomahawkSipMessage : public Jreen::Payload
const QString key() const;
bool visible() const;
private:
- QScopedPointer d_ptr;
+ QScopedPointer d_ptr;
};
#endif // ENTITYTIME_H
diff --git a/src/sip/jabber/tomahawksipmessagefactory.cpp b/src/accounts/xmpp/sip/tomahawkxmppmessagefactory.cpp
similarity index 80%
rename from src/sip/jabber/tomahawksipmessagefactory.cpp
rename to src/accounts/xmpp/sip/tomahawkxmppmessagefactory.cpp
index a45cc27f2..b20d4756a 100644
--- a/src/sip/jabber/tomahawksipmessagefactory.cpp
+++ b/src/accounts/xmpp/sip/tomahawkxmppmessagefactory.cpp
@@ -16,7 +16,7 @@
* along with Tomahawk. If not, see .
*/
-#include "tomahawksipmessagefactory.h"
+#include "tomahawkxmppmessagefactory.h"
#include
#include
@@ -26,29 +26,29 @@
using namespace Jreen;
-TomahawkSipMessageFactory::TomahawkSipMessageFactory()
+TomahawkXmppMessageFactory::TomahawkXmppMessageFactory()
{
m_depth = 0;
m_state = AtNowhere;
}
-TomahawkSipMessageFactory::~TomahawkSipMessageFactory()
+TomahawkXmppMessageFactory::~TomahawkXmppMessageFactory()
{
}
-QStringList TomahawkSipMessageFactory::features() const
+QStringList TomahawkXmppMessageFactory::features() const
{
return QStringList(TOMAHAWK_SIP_MESSAGE_NS);
}
-bool TomahawkSipMessageFactory::canParse(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes)
+bool TomahawkXmppMessageFactory::canParse(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes)
{
Q_UNUSED(uri);
Q_UNUSED(attributes);
return name == QLatin1String("tomahawk") && uri == TOMAHAWK_SIP_MESSAGE_NS;
}
-void TomahawkSipMessageFactory::handleStartElement(const QStringRef &name, const QStringRef &uri,
+void TomahawkXmppMessageFactory::handleStartElement(const QStringRef &name, const QStringRef &uri,
const QXmlStreamAttributes &attributes)
{
m_depth++;
@@ -83,7 +83,7 @@ void TomahawkSipMessageFactory::handleStartElement(const QStringRef &name, const
Q_UNUSED(attributes);
}
-void TomahawkSipMessageFactory::handleEndElement(const QStringRef &name, const QStringRef &uri)
+void TomahawkXmppMessageFactory::handleEndElement(const QStringRef &name, const QStringRef &uri)
{
if (m_depth == 3)
m_state = AtNowhere;
@@ -92,7 +92,7 @@ void TomahawkSipMessageFactory::handleEndElement(const QStringRef &name, const Q
m_depth--;
}
-void TomahawkSipMessageFactory::handleCharacterData(const QStringRef &text)
+void TomahawkXmppMessageFactory::handleCharacterData(const QStringRef &text)
{
/*if (m_state == AtUtc) {
//m_utc = Util::fromStamp(text.toString());
@@ -105,9 +105,9 @@ void TomahawkSipMessageFactory::handleCharacterData(const QStringRef &text)
Q_UNUSED(text);
}
-void TomahawkSipMessageFactory::serialize(Payload *extension, QXmlStreamWriter *writer)
+void TomahawkXmppMessageFactory::serialize(Payload *extension, QXmlStreamWriter *writer)
{
- TomahawkSipMessage *sipMessage = se_cast(extension);
+ TomahawkXmppMessage *sipMessage = se_cast(extension);
writer->writeStartElement(QLatin1String("tomahawk"));
writer->writeDefaultNamespace(TOMAHAWK_SIP_MESSAGE_NS);
@@ -137,10 +137,10 @@ void TomahawkSipMessageFactory::serialize(Payload *extension, QXmlStreamWriter *
writer->writeEndElement();
}
-Payload::Ptr TomahawkSipMessageFactory::createPayload()
+Payload::Ptr TomahawkXmppMessageFactory::createPayload()
{
if(m_visible)
- return Payload::Ptr(new TomahawkSipMessage(m_ip, m_port, m_uniqname, m_key));
+ return Payload::Ptr(new TomahawkXmppMessage(m_ip, m_port, m_uniqname, m_key));
else
- return Payload::Ptr(new TomahawkSipMessage());
+ return Payload::Ptr(new TomahawkXmppMessage());
}
diff --git a/src/sip/jabber/tomahawksipmessagefactory.h b/src/accounts/xmpp/sip/tomahawkxmppmessagefactory.h
similarity index 86%
rename from src/sip/jabber/tomahawksipmessagefactory.h
rename to src/accounts/xmpp/sip/tomahawkxmppmessagefactory.h
index a9e7a0db0..ab713f30f 100644
--- a/src/sip/jabber/tomahawksipmessagefactory.h
+++ b/src/accounts/xmpp/sip/tomahawkxmppmessagefactory.h
@@ -19,17 +19,17 @@
#ifndef ENTITYTIMEFACTORY_P_H
#define ENTITYTIMEFACTORY_P_H
-#include "tomahawksipmessage.h"
+#include "tomahawkxmppmessage.h"
#include
-#include "../sipdllmacro.h"
+#include "accounts/accountdllmacro.h"
-class SIPDLLEXPORT TomahawkSipMessageFactory : public Jreen::PayloadFactory
+class ACCOUNTDLLEXPORT TomahawkXmppMessageFactory : public Jreen::PayloadFactory
{
public:
- TomahawkSipMessageFactory();
- virtual ~TomahawkSipMessageFactory();
+ TomahawkXmppMessageFactory();
+ virtual ~TomahawkXmppMessageFactory();
QStringList features() const;
bool canParse(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes);
void handleStartElement(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes);
diff --git a/src/sip/jabber/xmlconsole.cpp b/src/accounts/xmpp/sip/xmlconsole.cpp
similarity index 100%
rename from src/sip/jabber/xmlconsole.cpp
rename to src/accounts/xmpp/sip/xmlconsole.cpp
diff --git a/src/sip/jabber/xmlconsole.h b/src/accounts/xmpp/sip/xmlconsole.h
similarity index 95%
rename from src/sip/jabber/xmlconsole.h
rename to src/accounts/xmpp/sip/xmlconsole.h
index 2cb617b5d..2f8e27846 100644
--- a/src/sip/jabber/xmlconsole.h
+++ b/src/accounts/xmpp/sip/xmlconsole.h
@@ -23,18 +23,18 @@
#include
#include
-#include
-#include
-#include
-#include
+#include
+#include
+#include
+#include
namespace Ui {
class XmlConsole;
}
-#include "../sipdllmacro.h"
+#include "accounts/accountdllmacro.h"
-class SIPDLLEXPORT XmlConsole : public QWidget, public Jreen::XmlStreamHandler
+class ACCOUNTDLLEXPORT XmlConsole : public QWidget, public Jreen::XmlStreamHandler
{
Q_OBJECT
diff --git a/src/sip/jabber/xmlconsole.ui b/src/accounts/xmpp/sip/xmlconsole.ui
similarity index 100%
rename from src/sip/jabber/xmlconsole.ui
rename to src/accounts/xmpp/sip/xmlconsole.ui
diff --git a/src/sip/jabber/jabber.cpp b/src/accounts/xmpp/sip/xmppsip.cpp
similarity index 77%
rename from src/sip/jabber/jabber.cpp
rename to src/accounts/xmpp/sip/xmppsip.cpp
index fa3295a4f..d89111ccb 100644
--- a/src/sip/jabber/jabber.cpp
+++ b/src/accounts/xmpp/sip/xmppsip.cpp
@@ -2,6 +2,7 @@
*
* Copyright 2010-2011, Dominik Schmidt
* Copyright 2010-2011, Christian Muehlhaeuser
+ * Copyright 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
@@ -17,14 +18,12 @@
* along with Tomahawk. If not, see .
*/
-#include "jabber.h"
-#include "ui_configwidget.h"
+#include "xmppsip.h"
#include "config.h"
-#include "tomahawksettings.h"
-#include "tomahawksipmessage.h"
-#include "tomahawksipmessagefactory.h"
+#include "tomahawkxmppmessage.h"
+#include "tomahawkxmppmessagefactory.h"
#include
#include
@@ -43,6 +42,10 @@
#include
#include
+#include
+#include
+#include
+
#ifndef ENABLE_HEADLESS
#include
#include
@@ -52,59 +55,33 @@
#include
#include "utils/logger.h"
-using namespace Jreen;
+using namespace Tomahawk;
+using namespace Accounts;
-SipPlugin*
-JabberFactory::createPlugin( const QString& pluginId )
-{
- return new JabberPlugin( pluginId.isEmpty() ? generateId() : pluginId );
-}
-
-
-QIcon
-JabberFactory::icon() const
-{
- return QIcon( ":/jabber-icon.png" );
-}
-
-
-JabberPlugin::JabberPlugin( const QString& pluginId )
- : SipPlugin( pluginId )
- , m_state( Disconnected )
+XmppSipPlugin::XmppSipPlugin( Account *account )
+ : SipPlugin( account )
#ifndef ENABLE_HEADLESS
, m_menu( 0 )
, m_xmlConsole( 0 )
#endif
+ , m_state( Account::Disconnected )
{
qDebug() << Q_FUNC_INFO;
- m_currentUsername = accountName();
+ m_currentUsername = readUsername();
+
m_currentServer = readServer();
m_currentPassword = readPassword();
m_currentPort = readPort();
-#ifndef ENABLE_HEADLESS
- m_configWidget = QWeakPointer< QWidget >( new QWidget );
- m_ui = new Ui_JabberConfig;
- m_ui->setupUi( m_configWidget.data() );
- m_configWidget.data()->setVisible( false );
-
- m_ui->jabberUsername->setText( m_currentUsername );
- m_ui->jabberPassword->setText( m_currentPassword );
- m_ui->jabberServer->setText( m_currentServer );
- m_ui->jabberPort->setValue( m_currentPort );
- m_ui->jidExistsLabel->hide();
- connect( m_ui->jabberUsername, SIGNAL( textChanged( QString ) ), SLOT( onCheckJidExists( QString ) ) );
-#endif
-
// setup JID object
- Jreen::JID jid = Jreen::JID( accountName() );
+ Jreen::JID jid = Jreen::JID( readUsername() );
// general client setup
m_client = new Jreen::Client( jid, m_currentPassword );
setupClientHelper();
- m_client->registerPayload(new TomahawkSipMessageFactory);
+ m_client->registerPayload( new TomahawkXmppMessageFactory );
m_currentResource = QString::fromAscii( "tomahawk%1" ).arg( QString::number( qrand() % 10000 ) );
m_client->setResource( m_currentResource );
@@ -158,8 +135,7 @@ JabberPlugin::JabberPlugin( const QString& pluginId )
#endif
}
-
-JabberPlugin::~JabberPlugin()
+XmppSipPlugin::~XmppSipPlugin()
{
delete m_avatarManager;
delete m_roster;
@@ -167,67 +143,29 @@ JabberPlugin::~JabberPlugin()
delete m_xmlConsole;
#endif
delete m_client;
- delete m_ui;
-}
-
-
-const QString
-JabberPlugin::name() const
-{
- return QString( MYNAME );
-}
-
-
-const QString
-JabberPlugin::friendlyName() const
-{
- return QString( "Jabber" );
-}
-
-
-const QString
-JabberPlugin::accountName() const
-{
- return TomahawkSettings::instance()->value( pluginId() + "/username" ).toString();
}
#ifndef ENABLE_HEADLESS
QMenu*
-JabberPlugin::menu()
+XmppSipPlugin::menu()
{
return m_menu;
}
-
-
-QWidget*
-JabberPlugin::configWidget()
-{
- return m_configWidget.data();
-}
-
-
-QIcon
-JabberPlugin::icon() const
-{
- return QIcon( ":/jabber-icon.png" );
-}
#endif
-
-bool
-JabberPlugin::connectPlugin( bool startup )
+void
+XmppSipPlugin::connectPlugin()
{
- Q_UNUSED( startup );
qDebug() << Q_FUNC_INFO;
- if(m_client->isConnected())
+ if( m_client->isConnected() )
{
qDebug() << Q_FUNC_INFO << "Already connected to server, not connecting again...";
- return true; //FIXME: should i return false here?!
+ return; //FIXME: should i return false here?!
}
- qDebug() << "Connecting to the XMPP server..." << m_client->jid().full();
+ qDebug() << "Connecting to the Xmpp server..." << m_client->jid().full();
//FIXME: we're badly workarounding some missing reconnection api here, to be fixed soon
QTimer::singleShot( 1000, m_client, SLOT( connectToServer() ) );
@@ -235,21 +173,21 @@ JabberPlugin::connectPlugin( bool startup )
if ( m_client->connection() )
connect(m_client->connection(), SIGNAL(error(SocketError)), SLOT(onError(SocketError)));
- m_state = Connecting;
+ m_state = Account::Connecting;
emit stateChanged( m_state );
- return true;
+ return;
}
void
-JabberPlugin::disconnectPlugin()
+XmppSipPlugin::disconnectPlugin()
{
if (!m_client->isConnected())
{
- if ( m_state != Disconnected ) // might be Connecting
+ if ( m_state != Account::Disconnected ) // might be Connecting
{
- m_state = Disconnected;
- emit stateChanged( m_state );
+ m_state = Account::Disconnected;
+ emit stateChanged( m_state );
}
return;
}
@@ -262,13 +200,13 @@ JabberPlugin::disconnectPlugin()
m_peers.clear();
m_client->disconnectFromServer( true );
- m_state = Disconnecting;
+ m_state = Account::Disconnecting;
emit stateChanged( m_state );
}
void
-JabberPlugin::onConnect()
+XmppSipPlugin::onConnect()
{
// qDebug() << Q_FUNC_INFO;
@@ -280,7 +218,7 @@ JabberPlugin::onConnect()
emit jidChanged( m_client->jid().full() );
}
- qDebug() << "Connected to jabber as:" << m_client->jid().full();
+ qDebug() << "Connected to xmpp as:" << m_client->jid().full();
// set presence to least valid value
m_client->setPresence(Jreen::Presence::XA, "Got Tomahawk? http://gettomahawk.com", -127);
@@ -303,7 +241,7 @@ JabberPlugin::onConnect()
//connect( m_room, SIGNAL( messageReceived( Jreen::Message, bool ) ), this, SLOT( onNewMessage( Jreen::Message ) ) );
//connect( m_room, SIGNAL( presenceReceived( Jreen::Presence, const Jreen::MUCRoom::Participant* ) ), this, SLOT( onNewPresence( Jreen::Presence ) ) );
- m_state = Connected;
+ m_state = Account::Connected;
emit stateChanged( m_state );
addMenuHelper();
@@ -311,7 +249,7 @@ JabberPlugin::onConnect()
void
-JabberPlugin::onDisconnect( Jreen::Client::DisconnectReason reason )
+XmppSipPlugin::onDisconnect( Jreen::Client::DisconnectReason reason )
{
qDebug() << Q_FUNC_INFO;
@@ -321,7 +259,7 @@ JabberPlugin::onDisconnect( Jreen::Client::DisconnectReason reason )
break;
case Jreen::Client::AuthorizationError:
- emit error( SipPlugin::AuthError, errorMessage( reason ) );
+ emit error( Account::AuthError, errorMessage( reason ) );
break;
case Jreen::Client::HostUnknown:
@@ -332,7 +270,7 @@ JabberPlugin::onDisconnect( Jreen::Client::DisconnectReason reason )
case Jreen::Client::SystemShutdown:
case Jreen::Client::Conflict:
case Jreen::Client::Unknown:
- emit error( SipPlugin::ConnectionError, errorMessage( reason ) );
+ emit error( Account::ConnectionError, errorMessage( reason ) );
break;
default:
@@ -340,7 +278,7 @@ JabberPlugin::onDisconnect( Jreen::Client::DisconnectReason reason )
Q_ASSERT(false);
break;
}
- m_state = Disconnected;
+ m_state = Account::Disconnected;
emit stateChanged( m_state );
removeMenuHelper();
@@ -353,14 +291,14 @@ JabberPlugin::onDisconnect( Jreen::Client::DisconnectReason reason )
void
-JabberPlugin::onError( const Jreen::Connection::SocketError& e )
+XmppSipPlugin::onError( const Jreen::Connection::SocketError& e )
{
tDebug() << "JABBER error:" << e;
}
QString
-JabberPlugin::errorMessage( Jreen::Client::DisconnectReason reason )
+XmppSipPlugin::errorMessage( Jreen::Client::DisconnectReason reason )
{
switch( reason )
{
@@ -402,7 +340,7 @@ JabberPlugin::errorMessage( Jreen::Client::DisconnectReason reason )
break;
}
- m_state = Disconnected;
+ m_state = Account::Disconnected;
emit stateChanged( m_state );
return QString();
@@ -410,7 +348,7 @@ JabberPlugin::errorMessage( Jreen::Client::DisconnectReason reason )
void
-JabberPlugin::sendMsg( const QString& to, const QString& msg )
+XmppSipPlugin::sendMsg( const QString& to, const QString& msg )
{
qDebug() << Q_FUNC_INFO << to << msg;
@@ -426,16 +364,16 @@ JabberPlugin::sendMsg( const QString& to, const QString& msg )
QVariant v = parser.parse( msg.toAscii(), &ok );
if ( !ok || v.type() != QVariant::Map )
{
- qDebug() << "Invalid JSON in XMPP msg";
+ qDebug() << "Invalid JSON in Xmpp msg";
return;
}
QVariantMap m = v.toMap();
/*******************************************************/
- TomahawkSipMessage *sipMessage;
+ TomahawkXmppMessage *sipMessage;
if(m["visible"].toBool())
{
- sipMessage = new TomahawkSipMessage( m["ip"].toString(),
+ sipMessage = new TomahawkXmppMessage( m["ip"].toString(),
m["port"].toInt(),
m["uniqname"].toString(),
m["key"].toString()
@@ -443,7 +381,7 @@ JabberPlugin::sendMsg( const QString& to, const QString& msg )
}
else
{
- sipMessage = new TomahawkSipMessage();
+ sipMessage = new TomahawkXmppMessage();
}
qDebug() << "Send sip messsage to " << to;
@@ -456,7 +394,7 @@ JabberPlugin::sendMsg( const QString& to, const QString& msg )
void
-JabberPlugin::broadcastMsg( const QString& msg )
+XmppSipPlugin::broadcastMsg( const QString& msg )
{
qDebug() << Q_FUNC_INFO;
@@ -471,7 +409,7 @@ JabberPlugin::broadcastMsg( const QString& msg )
void
-JabberPlugin::addContact( const QString& jid, const QString& msg )
+XmppSipPlugin::addContact( const QString& jid, const QString& msg )
{
// Add contact to the Tomahawk group on the roster
@@ -486,30 +424,31 @@ JabberPlugin::addContact( const QString& jid, const QString& msg )
void
-JabberPlugin::showAddFriendDialog()
+XmppSipPlugin::showAddFriendDialog()
{
#ifndef ENABLE_HEADLESS
bool ok;
QString id = QInputDialog::getText( TomahawkUtils::tomahawkWindow(), tr( "Add Friend" ),
- tr( "Enter Jabber ID:" ), QLineEdit::Normal, "", &ok ).trimmed();
+ tr( "Enter Xmpp ID:" ), QLineEdit::Normal, "", &ok ).trimmed();
+
if ( !ok )
return;
- qDebug() << "Attempting to add jabber contact to roster:" << id;
+ qDebug() << "Attempting to add xmpp contact to roster:" << id;
addContact( id );
#endif
}
QString
-JabberPlugin::defaultSuffix() const
+XmppSipPlugin::defaultSuffix() const
{
- return "@jabber.org";
+ return "@xmpp.org";
}
void
-JabberPlugin::showXmlConsole()
+XmppSipPlugin::showXmlConsole()
{
#ifndef ENABLE_HEADLESS
m_xmlConsole->show();
@@ -518,14 +457,21 @@ JabberPlugin::showXmlConsole()
void
-JabberPlugin::checkSettings()
+XmppSipPlugin::checkSettings()
+{
+ configurationChanged();
+}
+
+
+void
+XmppSipPlugin::configurationChanged()
{
bool reconnect = false;
QString username, password, server;
int port;
- username = accountName();
+ username = readUsername();
password = readPassword();
server = readServer();
port = readPort();
@@ -554,7 +500,10 @@ JabberPlugin::checkSettings()
if ( !m_currentUsername.contains( '@' ) )
{
m_currentUsername += defaultSuffix();
- TomahawkSettings::instance()->setValue( pluginId() + "/username", m_currentUsername );
+ QVariantHash credentials = m_account->credentials();
+ credentials[ "username" ] = m_currentUsername;
+ m_account->setCredentials( credentials );
+ m_account->sync();
}
if ( reconnect )
@@ -565,12 +514,11 @@ JabberPlugin::checkSettings()
setupClientHelper();
qDebug() << Q_FUNC_INFO << "Updated settings";
- connectPlugin( false );
+ connectPlugin();
}
}
-
-void JabberPlugin::setupClientHelper()
+void XmppSipPlugin::setupClientHelper()
{
Jreen::JID jid = Jreen::JID( m_currentUsername );
m_client->setJID( jid );
@@ -590,13 +538,12 @@ void JabberPlugin::setupClientHelper()
}
}
-
-void JabberPlugin::addMenuHelper()
+void XmppSipPlugin::addMenuHelper()
{
#ifndef ENABLE_HEADLESS
if( !m_menu )
{
- m_menu = new QMenu( QString( "%1 (" ).arg( friendlyName() ).append( accountName() ).append(")" ) );
+ m_menu = new QMenu( QString( "%1 (" ).arg( friendlyName() ).append( readUsername() ).append(")" ) );
QAction* addFriendAction = m_menu->addAction( tr( "Add Friend..." ) );
connect( addFriendAction, SIGNAL( triggered() ), this, SLOT( showAddFriendDialog() ) );
@@ -612,8 +559,7 @@ void JabberPlugin::addMenuHelper()
#endif
}
-
-void JabberPlugin::removeMenuHelper()
+void XmppSipPlugin::removeMenuHelper()
{
#ifndef ENABLE_HEADLESS
if( m_menu )
@@ -627,9 +573,9 @@ void JabberPlugin::removeMenuHelper()
}
-void JabberPlugin::onNewMessage( const Jreen::Message& message )
+void XmppSipPlugin::onNewMessage( const Jreen::Message& message )
{
- if ( m_state != Connected )
+ if ( m_state != Account::Connected )
return;
// qDebug() << Q_FUNC_INFO << "message type" << message.subtype();
@@ -668,10 +614,10 @@ void JabberPlugin::onNewMessage( const Jreen::Message& message )
}
-void JabberPlugin::onPresenceReceived( const Jreen::RosterItem::Ptr &item, const Jreen::Presence& presence )
+void XmppSipPlugin::onPresenceReceived( const Jreen::RosterItem::Ptr &item, const Jreen::Presence& presence )
{
Q_UNUSED(item);
- if ( m_state != Connected )
+ if ( m_state != Account::Connected )
return;
Jreen::JID jid = presence.from();
@@ -712,9 +658,9 @@ void JabberPlugin::onPresenceReceived( const Jreen::RosterItem::Ptr &item, const
}
-void JabberPlugin::onSubscriptionReceived( const Jreen::RosterItem::Ptr& item, const Jreen::Presence& presence )
+void XmppSipPlugin::onSubscriptionReceived( const Jreen::RosterItem::Ptr& item, const Jreen::Presence& presence )
{
- if ( m_state != Connected )
+ if ( m_state != Account::Connected )
return;
// qDebug() << Q_FUNC_INFO << "presence type:" << presence.subtype();
@@ -766,7 +712,7 @@ void JabberPlugin::onSubscriptionReceived( const Jreen::RosterItem::Ptr& item, c
void
-JabberPlugin::onSubscriptionRequestConfirmed( int result )
+XmppSipPlugin::onSubscriptionRequestConfirmed( int result )
{
#ifndef ENABLE_HEADLESS
qDebug() << Q_FUNC_INFO << result;
@@ -803,9 +749,9 @@ JabberPlugin::onSubscriptionRequestConfirmed( int result )
}
-void JabberPlugin::onNewIq( const Jreen::IQ& iq )
+void XmppSipPlugin::onNewIq( const Jreen::IQ& iq )
{
- if ( m_state != Connected )
+ if ( m_state != Account::Connected )
return;
Jreen::IQReply *reply = qobject_cast< Jreen::IQReply* >( sender() );
@@ -855,7 +801,7 @@ void JabberPlugin::onNewIq( const Jreen::IQ& iq )
}*/
else
{
- TomahawkSipMessage::Ptr sipMessage = iq.payload< TomahawkSipMessage >();
+ TomahawkXmppMessage::Ptr sipMessage = iq.payload< TomahawkXmppMessage >();
if(sipMessage)
{
iq.accept();
@@ -885,7 +831,7 @@ void JabberPlugin::onNewIq( const Jreen::IQ& iq )
}
-bool JabberPlugin::presenceMeansOnline( Jreen::Presence::Type p )
+bool XmppSipPlugin::presenceMeansOnline( Jreen::Presence::Type p )
{
switch( p )
{
@@ -900,7 +846,7 @@ bool JabberPlugin::presenceMeansOnline( Jreen::Presence::Type p )
}
-void JabberPlugin::handlePeerStatus( const Jreen::JID& jid, Jreen::Presence::Type presenceType )
+void XmppSipPlugin::handlePeerStatus( const Jreen::JID& jid, Jreen::Presence::Type presenceType )
{
QString fulljid = jid.full();
@@ -950,11 +896,11 @@ void JabberPlugin::handlePeerStatus( const Jreen::JID& jid, Jreen::Presence::Typ
}
-void JabberPlugin::onNewAvatar( const QString& jid )
+void XmppSipPlugin::onNewAvatar( const QString& jid )
{
#ifndef ENABLE_HEADLESS
// qDebug() << Q_FUNC_INFO << jid;
- if ( m_state != Connected )
+ if ( m_state != Account::Connected )
return;
Q_ASSERT( !m_avatarManager->avatar( jid ).isNull() );
@@ -980,84 +926,46 @@ void JabberPlugin::onNewAvatar( const QString& jid )
bool
-JabberPlugin::readXmlConsoleEnabled()
+XmppSipPlugin::readXmlConsoleEnabled()
{
- return TomahawkSettings::instance()->value( pluginId() + "/xmlconsole", QVariant( false ) ).toBool();
+ QVariantHash configuration = m_account->configuration();
+ return configuration.contains( "xmlconsole" ) && configuration[ "xmlconsole" ].toBool();
}
QString
-JabberPlugin::readPassword()
+XmppSipPlugin::readUsername()
{
- return TomahawkSettings::instance()->value( pluginId() + "/password" ).toString();
+ QVariantHash credentials = m_account->credentials();
+ return credentials.contains( "username" ) ? credentials[ "username" ].toString() : QString();
+}
+
+QString
+XmppSipPlugin::readPassword()
+{
+ QVariantHash credentials = m_account->credentials();
+ return credentials.contains( "password" ) ? credentials[ "password" ].toString() : QString();
}
int
-JabberPlugin::readPort()
+XmppSipPlugin::readPort()
{
- return TomahawkSettings::instance()->value( pluginId() + "/port", 5222 ).toInt();
+ QVariantHash configuration = m_account->configuration();
+ return configuration.contains( "port" ) ? configuration[ "port" ].toInt() : 5222;
}
QString
-JabberPlugin::readServer()
+XmppSipPlugin::readServer()
{
- return TomahawkSettings::instance()->value( pluginId() + "/server" ).toString();
+ QVariantHash configuration = m_account->configuration();
+ return configuration.contains( "server" ) ? configuration[ "server" ].toString() : QString();
}
-void
-JabberPlugin::onCheckJidExists( QString jid )
-{
- for ( int i=0; isipPlugins().count(); i++ )
- {
- QString savedUsername = TomahawkSettings::instance()->value(
- TomahawkSettings::instance()->sipPlugins().at( i ) + "/username" ).toString();
- QStringList splitUserName = TomahawkSettings::instance()->value(
- TomahawkSettings::instance()->sipPlugins().at( i ) + "/username" ).toString().split("@");
- QString server = TomahawkSettings::instance()->value(
- TomahawkSettings::instance()->sipPlugins().at( i ) + "/server" ).toString();
-
- if ( ( savedUsername == jid || splitUserName.contains( jid ) ) &&
- server == m_ui->jabberServer->text() && !jid.trimmed().isEmpty() )
- {
- m_ui->jidExistsLabel->show();
- // the already jid exists
- emit dataError( true );
- return;
- }
- }
- m_ui->jidExistsLabel->hide();
- emit dataError( false );
-}
-
-
-void
-JabberPlugin::saveConfig()
-{
- TomahawkSettings::instance()->setValue( pluginId() + "/username", m_ui->jabberUsername->text() );
- TomahawkSettings::instance()->setValue( pluginId() + "/password", m_ui->jabberPassword->text() );
- TomahawkSettings::instance()->setValue( pluginId() + "/port", m_ui->jabberPort->value() );
- TomahawkSettings::instance()->setValue( pluginId() + "/server", m_ui->jabberServer->text() );
-
- checkSettings();
-}
-
-
-void
-JabberPlugin::deletePlugin()
-{
- TomahawkSettings::instance()->remove( pluginId() );
-}
-
-
-SipPlugin::ConnectionState
-JabberPlugin::connectionState() const
+Account::ConnectionState
+XmppSipPlugin::connectionState() const
{
return m_state;
}
-
-#ifndef GOOGLE_WRAPPER
-Q_EXPORT_PLUGIN2( sipfactory, JabberFactory )
-#endif
diff --git a/src/sip/jabber/jabber.h b/src/accounts/xmpp/sip/xmppsip.h
similarity index 70%
rename from src/sip/jabber/jabber.h
rename to src/accounts/xmpp/sip/xmppsip.h
index 0b706056d..45cb5d8c0 100644
--- a/src/sip/jabber/jabber.h
+++ b/src/accounts/xmpp/sip/xmppsip.h
@@ -2,6 +2,7 @@
*
* Copyright 2010-2011, Dominik Schmidt
* Copyright 2010-2011, Christian Muehlhaeuser
+ * Copyright 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
@@ -17,8 +18,8 @@
* along with Tomahawk. If not, see .
*/
-#ifndef JABBER_H
-#define JABBER_H
+#ifndef XMPPSIP_H
+#define XMPPSIP_H
#include "sip/SipPlugin.h"
@@ -45,70 +46,49 @@
#include
#endif
-#define MYNAME "SIPJREEN"
#define TOMAHAWK_FEATURE QLatin1String( "tomahawk:sip:v1" )
#define TOMAHAWK_CAP_NODE_NAME QLatin1String( "http://tomahawk-player.org/" )
-#include "../sipdllmacro.h"
+#include "accounts/accountdllmacro.h"
-class Ui_JabberConfig;
-
-class SIPDLLEXPORT JabberFactory : public SipPluginFactory
-{
- Q_OBJECT
- Q_INTERFACES( SipPluginFactory )
-
-public:
- JabberFactory() {}
- virtual ~JabberFactory() {}
-
- virtual QString prettyName() const { return "Jabber"; }
- virtual QString factoryId() const { return "sipjabber"; }
- virtual QIcon icon() const;
- virtual SipPlugin* createPlugin( const QString& pluginId );
-};
-
-class SIPDLLEXPORT JabberPlugin : public SipPlugin
+class ACCOUNTDLLEXPORT XmppSipPlugin : public SipPlugin
{
Q_OBJECT
public:
- JabberPlugin( const QString& pluginId );
- virtual ~JabberPlugin();
+ XmppSipPlugin( Tomahawk::Accounts::Account* account );
+ virtual ~XmppSipPlugin();
//FIXME: Make this more correct
virtual bool isValid() const { return true; }
- virtual const QString name() const;
- virtual const QString friendlyName() const;
- virtual const QString accountName() const;
- virtual ConnectionState connectionState() const;
#ifndef ENABLE_HEADLESS
virtual QMenu* menu();
- virtual QIcon icon() const;
- virtual QWidget* configWidget();
#endif
- virtual void saveConfig();
- virtual void deletePlugin();
+
+ // used by XmppAccount to expose connection state and controls
+ Tomahawk::Accounts::Account::ConnectionState connectionState() const;
signals:
- void dataError( bool exists );
void jidChanged( const QString& );
+ // Used by XmppAccount
+ void stateChanged( Tomahawk::Accounts::Account::ConnectionState state );
+ void error( int errorId, const QString& errorStr );
+
public slots:
- virtual bool connectPlugin( bool startup );
- void disconnectPlugin();
- void checkSettings();
- void sendMsg( const QString& to, const QString& msg );
+ virtual void connectPlugin();
+ virtual void disconnectPlugin();
+ virtual void checkSettings();
+ virtual void configurationChanged();
+ virtual void sendMsg( const QString& to, const QString& msg );
void broadcastMsg( const QString &msg );
- void addContact( const QString &jid, const QString& msg = QString() );
+ virtual void addContact( const QString &jid, const QString& msg = QString() );
void showAddFriendDialog();
protected:
virtual QString defaultSuffix() const;
- Ui_JabberConfig* m_ui; // so the google wrapper can change the config dialog a bit
-
private slots:
void showXmlConsole();
void onConnect();
@@ -122,10 +102,10 @@ private slots:
void onError( const Jreen::Connection::SocketError& e );
void onNewIq( const Jreen::IQ &iq );
void onNewAvatar( const QString &jid );
- void onCheckJidExists( QString jid );
private:
bool readXmlConsoleEnabled();
+ QString readUsername();
QString readPassword();
QString readServer();
int readPort();
@@ -138,15 +118,11 @@ private:
bool presenceMeansOnline( Jreen::Presence::Type p );
void handlePeerStatus( const Jreen::JID &jid, Jreen::Presence::Type presenceType );
- using SipPlugin::errorMessage;
-
QString m_currentUsername;
QString m_currentPassword;
QString m_currentServer;
int m_currentPort;
- ConnectionState m_state;
-
- QWeakPointer< QWidget > m_configWidget;
+ Tomahawk::Accounts::Account::ConnectionState m_state;
QString m_currentResource;
diff --git a/src/sip/jabber/jabber-icon.png b/src/accounts/xmpp/xmpp-icon.png
similarity index 100%
rename from src/sip/jabber/jabber-icon.png
rename to src/accounts/xmpp/xmpp-icon.png
diff --git a/src/accounts/xmpp/xmppaccount.cpp b/src/accounts/xmpp/xmppaccount.cpp
new file mode 100644
index 000000000..1c23f45c3
--- /dev/null
+++ b/src/accounts/xmpp/xmppaccount.cpp
@@ -0,0 +1,114 @@
+/* === This file is part of Tomahawk Player - ===
+ *
+ * Copyright 2010-2011, Christian Muehlhaeuser
+ * Copyright 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 "xmppaccount.h"
+#include "xmppconfigwidget.h"
+#include "sip/SipPlugin.h"
+#include "ui_xmppconfigwidget.h"
+
+#include
+
+namespace Tomahawk
+{
+
+namespace Accounts
+{
+
+Account*
+XmppAccountFactory::createAccount( const QString& accountId )
+{
+ return new XmppAccount( accountId.isEmpty() ? Tomahawk::Accounts::generateId( factoryId() ) : accountId );
+}
+
+
+XmppAccount::XmppAccount( const QString &accountId )
+ : Account( accountId )
+{
+ setAccountServiceName( "XMPP (Jabber)" );
+ setTypes( SipType );
+
+ m_configWidget = QWeakPointer< QWidget >( new XmppConfigWidget( this, 0 ) );
+}
+
+
+XmppAccount::~XmppAccount()
+{
+ delete m_xmppSipPlugin.data();
+}
+
+
+void
+XmppAccount::authenticate()
+{
+ if ( connectionState() != Account::Connected )
+ sipPlugin()->connectPlugin();
+}
+
+
+void
+XmppAccount::deauthenticate()
+{
+ if ( connectionState() != Account::Disconnected )
+ sipPlugin()->disconnectPlugin();
+}
+
+bool
+XmppAccount::isAuthenticated() const
+{
+ return m_xmppSipPlugin.data()->connectionState() == Account::Connected;
+}
+
+
+Account::ConnectionState
+XmppAccount::connectionState() const
+{
+ return m_xmppSipPlugin.data()->connectionState();
+}
+
+void
+XmppAccount::saveConfig()
+{
+ if ( !m_configWidget.isNull() )
+ static_cast< XmppConfigWidget* >( m_configWidget.data() )->saveConfig();
+}
+
+
+SipPlugin*
+XmppAccount::sipPlugin()
+{
+ if ( m_xmppSipPlugin.isNull() )
+ {
+ m_xmppSipPlugin = QWeakPointer< XmppSipPlugin >( new XmppSipPlugin( this ) );
+
+ connect( m_xmppSipPlugin.data(), SIGNAL( stateChanged( Tomahawk::Accounts::Account::ConnectionState ) ), this, SIGNAL( connectionStateChanged( Tomahawk::Accounts::Account::ConnectionState ) ) );
+ connect( m_xmppSipPlugin.data(), SIGNAL( error( int, QString ) ), this, SIGNAL( error( int, QString ) ) );
+
+ return m_xmppSipPlugin.data();
+ }
+ return m_xmppSipPlugin.data();
+}
+
+
+}
+
+}
+
+#ifndef GOOGLE_WRAPPER
+Q_EXPORT_PLUGIN2( Tomahawk::Accounts::AccountFactory, Tomahawk::Accounts::XmppAccountFactory )
+#endif
diff --git a/src/accounts/xmpp/xmppaccount.h b/src/accounts/xmpp/xmppaccount.h
new file mode 100644
index 000000000..a6c50ae20
--- /dev/null
+++ b/src/accounts/xmpp/xmppaccount.h
@@ -0,0 +1,89 @@
+/* === This file is part of Tomahawk Player - ===
+ *
+ * Copyright 2010-2011, Dominik Schmidt
+ * Copyright 2010-2011, Christian Muehlhaeuser
+ * Copyright 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 XMPPACCOUNT_H
+#define XMPPACCOUNT_H
+
+#include "sip/xmppsip.h"
+#include "accounts/accountdllmacro.h"
+#include "accounts/Account.h"
+
+#define MYNAME "ACCOUNTJABBER"
+
+class Ui_XmppConfigWidget;
+
+namespace Tomahawk
+{
+
+namespace Accounts
+{
+
+class ACCOUNTDLLEXPORT XmppAccountFactory : public AccountFactory
+{
+ Q_OBJECT
+ Q_INTERFACES( Tomahawk::Accounts::AccountFactory )
+
+ // for settings access
+ friend class XmppConfigWidget;
+public:
+ XmppAccountFactory() {}
+ virtual ~XmppAccountFactory() {}
+
+ QString prettyName() const { return "XMPP (Jabber)"; }
+ QString description() const { return tr( "Log on to your Jabber/XMPP account to connect to your friends" ); }
+ QString factoryId() const { return "xmppaccount"; }
+ QPixmap icon() const { return QPixmap( ":/xmpp-icon.png" ); }
+ AccountTypes types() const { return AccountTypes( SipType ); };
+ Account* createAccount( const QString& pluginId = QString() );
+};
+
+class ACCOUNTDLLEXPORT XmppAccount : public Account
+{
+ Q_OBJECT
+
+public:
+ XmppAccount( const QString &accountId );
+ virtual ~XmppAccount();
+
+ QPixmap icon() const { return QPixmap( ":/xmpp-icon.png" ); }
+
+ void authenticate();
+ void deauthenticate();
+ bool isAuthenticated() const;
+
+ Tomahawk::InfoSystem::InfoPlugin* infoPlugin() { return 0; }
+ SipPlugin* sipPlugin();
+
+ QWidget* configurationWidget() { return m_configWidget.data(); }
+ QWidget* aclWidget() { return 0; }
+ void saveConfig();
+
+ virtual Tomahawk::Accounts::Account::ConnectionState connectionState() const;
+
+protected:
+ QWeakPointer< QWidget > m_configWidget; // so the google wrapper can change the config dialog a bit
+ QWeakPointer< XmppSipPlugin > m_xmppSipPlugin;
+};
+
+};
+
+};
+
+#endif
diff --git a/src/accounts/xmpp/xmppconfigwidget.cpp b/src/accounts/xmpp/xmppconfigwidget.cpp
new file mode 100644
index 000000000..b85b6e7c3
--- /dev/null
+++ b/src/accounts/xmpp/xmppconfigwidget.cpp
@@ -0,0 +1,108 @@
+/* === This file is part of Tomahawk Player - ===
+ *
+ * Copyright 2010-2011, Christian Muehlhaeuser
+ *
+ * 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 "xmppaccount.h"
+#include "xmppconfigwidget.h"
+#include "ui_xmppconfigwidget.h"
+
+#include
+
+#include
+#include
+
+namespace Tomahawk
+{
+
+namespace Accounts
+{
+
+XmppConfigWidget::XmppConfigWidget( XmppAccount* account, QWidget *parent ) :
+ QWidget( parent ),
+ m_ui( new Ui::XmppConfigWidget ),
+ m_account( account )
+{
+ m_ui->setupUi( this );
+
+ m_ui->xmppUsername->setText( account->credentials().contains( "username" ) ? account->credentials()[ "username" ].toString() : QString() );
+ m_ui->xmppPassword->setText( account->credentials().contains( "password" ) ? account->credentials()[ "password" ].toString() : QString() );
+ m_ui->xmppServer->setText( account->configuration().contains( "server" ) ? account->configuration()[ "server" ].toString() : QString() );
+ m_ui->xmppPort->setValue( account->configuration().contains( "port" ) ? account->configuration()[ "port" ].toInt() : 5222 );
+ m_ui->jidExistsLabel->hide();
+
+ connect( m_ui->xmppUsername, SIGNAL( textChanged( QString ) ), SLOT( onCheckJidExists( QString ) ) );
+}
+
+
+XmppConfigWidget::~XmppConfigWidget()
+{
+ delete m_ui;
+}
+
+void
+XmppConfigWidget::saveConfig()
+{
+ QVariantHash credentials = m_account->credentials();
+ credentials[ "username" ] = m_ui->xmppUsername->text().trimmed();
+ credentials[ "password" ] = m_ui->xmppPassword->text().trimmed();
+
+ QVariantHash configuration = m_account->configuration();
+ configuration[ "server" ] = m_ui->xmppServer->text().trimmed();
+ configuration[ "port" ] = m_ui->xmppPort->text().trimmed();
+
+ m_account->setAccountFriendlyName( m_ui->xmppUsername->text() );
+ m_account->setCredentials( credentials );
+ m_account->setConfiguration( configuration);
+ m_account->sync();
+
+ static_cast< XmppSipPlugin* >( m_account->sipPlugin() )->checkSettings();
+}
+
+
+void
+XmppConfigWidget::onCheckJidExists( QString jid )
+{
+ QList< Tomahawk::Accounts::Account* > accounts = Tomahawk::Accounts::AccountManager::instance()->accounts( Tomahawk::Accounts::SipType );
+ foreach( Tomahawk::Accounts::Account* account, accounts )
+ {
+ if ( account->accountId() == m_account->accountId() )
+ continue;
+
+ QString savedUsername = account->credentials()[ "username" ].toString();
+ QStringList savedSplitUsername = account->credentials()[ "username" ].toString().split("@");
+ QString savedServer = account->configuration()[ "server" ].toString();
+ int savedPort = account->configuration()[ "port" ].toInt();
+
+ if ( ( savedUsername == jid || savedSplitUsername.contains( jid ) ) &&
+ savedServer == m_ui->xmppServer->text() &&
+ savedPort == m_ui->xmppPort->value() &&
+ !jid.trimmed().isEmpty() )
+ {
+ m_ui->jidExistsLabel->show();
+ // the already jid exists
+ emit dataError( true );
+ return;
+ }
+ }
+ m_ui->jidExistsLabel->hide();
+ emit dataError( false );
+}
+
+
+}
+
+}
diff --git a/src/accounts/xmpp/xmppconfigwidget.h b/src/accounts/xmpp/xmppconfigwidget.h
new file mode 100644
index 000000000..93f41f44d
--- /dev/null
+++ b/src/accounts/xmpp/xmppconfigwidget.h
@@ -0,0 +1,68 @@
+/* === This file is part of Tomahawk Player - ===
+ *
+ * Copyright 2010-2011, Christian Muehlhaeuser
+ *
+ * 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 JABBERACCOUNTCONFIGWIDGET_H
+#define JABBERACCOUNTCONFIGWIDGET_H
+
+#include "accounts/accountdllmacro.h"
+
+#include
+
+namespace Ui
+{
+ class XmppConfigWidget;
+}
+
+namespace Tomahawk
+{
+
+namespace Accounts
+{
+
+class XmppAccount;
+class GoogleWrapper;
+
+
+class ACCOUNTDLLEXPORT XmppConfigWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit XmppConfigWidget( XmppAccount* account = 0, QWidget *parent = 0 );
+ virtual ~XmppConfigWidget();
+
+ void saveConfig();
+
+signals:
+ void dataError( bool exists );
+
+private slots:
+ void onCheckJidExists( QString jid );
+
+private:
+ Ui::XmppConfigWidget *m_ui;
+ XmppAccount *m_account;
+
+ friend class GoogleWrapper; // So google wrapper can modify the labels and text
+};
+
+}
+
+}
+
+#endif // TWITTERCONFIGWIDGET_H
diff --git a/src/sip/jabber/configwidget.ui b/src/accounts/xmpp/xmppconfigwidget.ui
similarity index 89%
rename from src/sip/jabber/configwidget.ui
rename to src/accounts/xmpp/xmppconfigwidget.ui
index cd5fd72b1..99876aa6a 100644
--- a/src/sip/jabber/configwidget.ui
+++ b/src/accounts/xmpp/xmppconfigwidget.ui
@@ -1,7 +1,7 @@
- JabberConfig
-
+ XmppConfigWidget
+
0
@@ -11,7 +11,7 @@
- Jabber Configuration
+ Xmpp Configuration
-
@@ -35,7 +35,7 @@
- :/jabber-icon.png
+ :/xmpp-icon.png
@@ -49,7 +49,7 @@
- Configure this Jabber account
+ Configure this Xmpp account
@@ -84,9 +84,9 @@
-
-
+
- Enter your Jabber login to connect with your friends using Tomahawk!
+ Enter your Xmpp login to connect with your friends using Tomahawk!
@@ -128,15 +128,15 @@
- Jabber ID:
+ Xmpp ID:
- jabberUsername
+ xmppUsername
-
-
+
0
@@ -160,12 +160,12 @@
Password:
- jabberPassword
+ xmppPassword
-
-
+
0
@@ -196,7 +196,7 @@
-
-
+
true
@@ -207,13 +207,13 @@
- Advanced Jabber Settings
+ Advanced Xmpp Settings
-
-
-
+
0
@@ -233,12 +233,12 @@
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
- jabberServer
+ xmppServer
-
-
+
0
@@ -248,7 +248,7 @@
-
-
+
Port:
@@ -258,7 +258,7 @@
-
-
+
0
diff --git a/src/sip/zeroconf/CMakeLists.txt b/src/accounts/zeroconf/CMakeLists.txt
similarity index 70%
rename from src/sip/zeroconf/CMakeLists.txt
rename to src/accounts/zeroconf/CMakeLists.txt
index 3a33cc577..772a24350 100644
--- a/src/sip/zeroconf/CMakeLists.txt
+++ b/src/accounts/zeroconf/CMakeLists.txt
@@ -4,15 +4,17 @@ include( ${QT_USE_FILE} )
add_definitions( ${QT_DEFINITIONS} )
add_definitions( -DQT_PLUGIN )
add_definitions( -DQT_SHARED )
-add_definitions( -DSIPDLLEXPORT_PRO )
+add_definitions( -DACCOUNTDLLEXPORT_PRO )
set( zeroconfSources
zeroconf.cpp
+ zeroconfaccount.cpp
)
set( zeroconfHeaders
zeroconf.h
tomahawkzeroconf.h
+ zeroconfaccount.h
)
include_directories( . ${CMAKE_CURRENT_BINARY_DIR} ..
@@ -22,7 +24,7 @@ include_directories( . ${CMAKE_CURRENT_BINARY_DIR} ..
qt4_wrap_ui( UI_SRCS configwidget.ui )
qt4_add_resources( RC_SRCS "resources.qrc" )
qt4_wrap_cpp( zeroconfMoc ${zeroconfHeaders} )
-add_library( tomahawk_sipzeroconf SHARED ${zeroconfSources} ${zeroconfMoc} ${RC_SRCS} ${UI_SRCS} )
+add_library( tomahawk_account_zeroconf MODULE ${zeroconfSources} ${zeroconfMoc} ${RC_SRCS} ${UI_SRCS} )
IF( WIN32 )
SET( OS_SPECIFIC_LINK_LIBRARIES
@@ -32,7 +34,7 @@ SET( OS_SPECIFIC_LINK_LIBRARIES
)
ENDIF( WIN32 )
-target_link_libraries( tomahawk_sipzeroconf
+target_link_libraries( tomahawk_account_zeroconf
${QT_LIBRARIES}
${OS_SPECIFIC_LINK_LIBRARIES}
${TOMAHAWK_LIBRARIES}
@@ -42,4 +44,4 @@ IF( APPLE )
# SET( CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS} "-undefined dynamic_lookup" )
ENDIF( APPLE )
-install( TARGETS tomahawk_sipzeroconf DESTINATION ${CMAKE_INSTALL_LIBDIR} )
+install( TARGETS tomahawk_account_zeroconf DESTINATION ${CMAKE_INSTALL_LIBDIR} )
\ No newline at end of file
diff --git a/src/sip/zeroconf/configwidget.ui b/src/accounts/zeroconf/configwidget.ui
similarity index 100%
rename from src/sip/zeroconf/configwidget.ui
rename to src/accounts/zeroconf/configwidget.ui
diff --git a/src/sip/zeroconf/resources.qrc b/src/accounts/zeroconf/resources.qrc
similarity index 100%
rename from src/sip/zeroconf/resources.qrc
rename to src/accounts/zeroconf/resources.qrc
diff --git a/src/sip/zeroconf/tomahawkzeroconf.h b/src/accounts/zeroconf/tomahawkzeroconf.h
similarity index 97%
rename from src/sip/zeroconf/tomahawkzeroconf.h
rename to src/accounts/zeroconf/tomahawkzeroconf.h
index f875ef1dd..f54b162e3 100644
--- a/src/sip/zeroconf/tomahawkzeroconf.h
+++ b/src/accounts/zeroconf/tomahawkzeroconf.h
@@ -30,10 +30,9 @@
#include "database/database.h"
#include "network/servent.h"
+#include "accounts/accountdllmacro.h"
-#include "../sipdllmacro.h"
-
-class SIPDLLEXPORT Node : public QObject
+class Node : public QObject
{
Q_OBJECT
@@ -61,7 +60,7 @@ public slots:
emit tomahawkHostFound( ip, port, "Unknown", nid );
this->deleteLater();
}
-
+
void resolve()
{
QHostInfo::lookupHost( ip, this, SLOT( resolved( QHostInfo ) ) );
@@ -74,7 +73,7 @@ private:
};
-class SIPDLLEXPORT TomahawkZeroconf : public QObject
+class ACCOUNTDLLEXPORT TomahawkZeroconf : public QObject
{
Q_OBJECT
diff --git a/src/sip/zeroconf/zeroconf-icon.png b/src/accounts/zeroconf/zeroconf-icon.png
similarity index 100%
rename from src/sip/zeroconf/zeroconf-icon.png
rename to src/accounts/zeroconf/zeroconf-icon.png
diff --git a/src/sip/zeroconf/zeroconf.cpp b/src/accounts/zeroconf/zeroconf.cpp
similarity index 81%
rename from src/sip/zeroconf/zeroconf.cpp
rename to src/accounts/zeroconf/zeroconf.cpp
index e983b4cdd..88fdf6016 100644
--- a/src/sip/zeroconf/zeroconf.cpp
+++ b/src/accounts/zeroconf/zeroconf.cpp
@@ -1,6 +1,7 @@
/* === This file is part of Tomahawk Player - ===
*
* Copyright 2010-2011, Christian Muehlhaeuser
+ * Copyright 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
@@ -24,20 +25,15 @@
#include "tomahawksettings.h"
#include "utils/logger.h"
+#include "zeroconfaccount.h"
+using namespace Tomahawk;
+using namespace Accounts;
-SipPlugin*
-ZeroconfFactory::createPlugin( const QString& pluginId )
-{
- return new ZeroconfPlugin( pluginId.isEmpty() ? generateId() : pluginId );
-}
-
-ZeroconfPlugin::ZeroconfPlugin() : SipPlugin( "" ) {}
-
-ZeroconfPlugin::ZeroconfPlugin ( const QString& pluginId )
- : SipPlugin( pluginId )
+ZeroconfPlugin::ZeroconfPlugin ( ZeroconfAccount* parent )
+ : SipPlugin( parent )
, m_zeroconf( 0 )
- , m_state( Disconnected )
+ , m_state( Account::Disconnected )
, m_cachedNodes()
{
qDebug() << Q_FUNC_INFO;
@@ -66,22 +62,15 @@ ZeroconfPlugin::friendlyName() const
return QString( MYNAME );
}
-SipPlugin::ConnectionState
+Account::ConnectionState
ZeroconfPlugin::connectionState() const
{
return m_state;
}
-#ifndef ENABLE_HEADLESS
-QIcon
-ZeroconfFactory::icon() const
-{
- return QIcon( ":/zeroconf-icon.png" );
-}
-#endif
-bool
-ZeroconfPlugin::connectPlugin( bool /*startup*/ )
+void
+ZeroconfPlugin::connectPlugin()
{
delete m_zeroconf;
m_zeroconf = new TomahawkZeroconf( Servent::instance()->port(), this );
@@ -89,7 +78,7 @@ ZeroconfPlugin::connectPlugin( bool /*startup*/ )
SLOT( lanHostFound( QString, int, QString, QString ) ) );
advertise();
- m_state = Connected;
+ m_state = Account::Connected;
foreach( const QStringList& nodeSet, m_cachedNodes )
{
@@ -99,15 +88,13 @@ ZeroconfPlugin::connectPlugin( bool /*startup*/ )
m_cachedNodes.clear();
m_advertisementTimer.start();
-
- return true;
}
void
ZeroconfPlugin::disconnectPlugin()
{
m_advertisementTimer.stop();
- m_state = Disconnected;
+ m_state = Account::Disconnected;
delete m_zeroconf;
m_zeroconf = 0;
@@ -118,7 +105,7 @@ ZeroconfPlugin::disconnectPlugin()
QIcon
ZeroconfPlugin::icon() const
{
- return QIcon( ":/zeroconf-icon.png" );
+ return account()->icon();
}
#endif
@@ -138,7 +125,7 @@ ZeroconfPlugin::lanHostFound( const QString& host, int port, const QString& name
qDebug() << "Found LAN host:" << host << port << nodeid;
- if ( m_state != Connected )
+ if ( m_state != Account::Connected )
{
qDebug() << "Not online, so not connecting.";
QStringList nodeSet;
@@ -153,5 +140,3 @@ ZeroconfPlugin::lanHostFound( const QString& host, int port, const QString& name
qDebug() << "Already connected to" << host;
}
-
-Q_EXPORT_PLUGIN2( sipfactory, ZeroconfFactory )
diff --git a/src/sip/zeroconf/zeroconf.h b/src/accounts/zeroconf/zeroconf.h
similarity index 69%
rename from src/sip/zeroconf/zeroconf.h
rename to src/accounts/zeroconf/zeroconf.h
index 9a4c660b6..98e8a865c 100644
--- a/src/sip/zeroconf/zeroconf.h
+++ b/src/accounts/zeroconf/zeroconf.h
@@ -1,6 +1,7 @@
/* === This file is part of Tomahawk Player - ===
*
* Copyright 2010-2011, Christian Muehlhaeuser
+ * Copyright 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
@@ -20,55 +21,45 @@
#define ZEROCONF_H
#include "sip/SipPlugin.h"
+#include "accounts/Account.h"
#include "tomahawkzeroconf.h"
-#include "../sipdllmacro.h"
+#include "../accountdllmacro.h"
#include
#define MYNAME "Local Network"
-class SIPDLLEXPORT ZeroconfFactory : public SipPluginFactory
+namespace Tomahawk
+{
+namespace Accounts
{
- Q_OBJECT
- Q_INTERFACES( SipPluginFactory )
-public:
- ZeroconfFactory() {}
- virtual ~ZeroconfFactory() {}
- virtual QString factoryId() const { return "sipzeroconf"; }
- virtual QString prettyName() const { return "Local Network"; }
- virtual bool isUnique() const { return true; }
-#ifndef ENABLE_HEADLESS
- virtual QIcon icon() const;
-#endif
+class ZeroconfAccount;
- virtual SipPlugin* createPlugin ( const QString& pluginId = QString() );
-};
-
-class SIPDLLEXPORT ZeroconfPlugin : public SipPlugin
+class ACCOUNTDLLEXPORT ZeroconfPlugin : public SipPlugin
{
Q_OBJECT
public:
- ZeroconfPlugin();
- ZeroconfPlugin( const QString& pluginId );
+ ZeroconfPlugin( ZeroconfAccount* acc );
virtual ~ZeroconfPlugin();
virtual const QString name() const;
virtual const QString friendlyName() const;
virtual const QString accountName() const;
- virtual ConnectionState connectionState() const;
+ virtual Account::ConnectionState connectionState() const;
virtual bool isValid() const { return true; }
#ifndef ENABLE_HEADLESS
virtual QIcon icon() const;
#endif
virtual void checkSettings() {}
+ virtual void configurationChanged() {}
public slots:
- virtual bool connectPlugin( bool startup );
+ void connectPlugin();
void disconnectPlugin();
void advertise();
@@ -82,9 +73,12 @@ private slots:
private:
TomahawkZeroconf* m_zeroconf;
- ConnectionState m_state;
+ Account::ConnectionState m_state;
QVector m_cachedNodes;
QTimer m_advertisementTimer;
};
+}
+}
+
#endif
diff --git a/src/accounts/zeroconf/zeroconfaccount.cpp b/src/accounts/zeroconf/zeroconfaccount.cpp
new file mode 100644
index 000000000..97548ecbc
--- /dev/null
+++ b/src/accounts/zeroconf/zeroconfaccount.cpp
@@ -0,0 +1,128 @@
+/* === This file is part of Tomahawk Player - ===
+ *
+ * Copyright 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 "zeroconfaccount.h"
+
+#include "sip/SipPlugin.h"
+#include "zeroconf.h"
+
+#include
+
+using namespace Tomahawk;
+using namespace Accounts;
+
+QPixmap* s_icon = 0;
+
+ZeroconfFactory::ZeroconfFactory()
+{
+#ifndef ENABLE_HEADLESS
+ if ( s_icon == 0 )
+ s_icon = new QPixmap( ":/zeroconf-icon.png" );
+#endif
+}
+
+
+ZeroconfFactory::~ZeroconfFactory()
+{
+ if ( s_icon )
+ {
+ delete s_icon;
+ s_icon = 0;
+ }
+}
+
+
+Account*
+ZeroconfFactory::createAccount( const QString& pluginId )
+{
+ return new ZeroconfAccount( pluginId.isEmpty() ? generateId( factoryId() ) : pluginId );
+}
+
+QPixmap
+ZeroconfFactory::icon() const
+{
+ return *s_icon;
+}
+
+
+ZeroconfAccount::ZeroconfAccount( const QString& accountId )
+ : Account( accountId )
+{
+ setAccountServiceName( "Local Network" );
+ setAccountFriendlyName( "Local Network" );
+
+ setTypes( SipType );
+}
+
+ZeroconfAccount::~ZeroconfAccount()
+{
+
+}
+
+QPixmap
+ZeroconfAccount::icon() const
+{
+ return *s_icon;
+}
+
+
+void
+ZeroconfAccount::authenticate()
+{
+ if ( !isAuthenticated() )
+ static_cast< ZeroconfPlugin* >( m_sipPlugin.data() )->connectPlugin();
+}
+
+
+void
+ZeroconfAccount::deauthenticate()
+{
+ if ( isAuthenticated() )
+ static_cast< ZeroconfPlugin* >( m_sipPlugin.data() )->disconnectPlugin();
+}
+
+
+bool
+ZeroconfAccount::isAuthenticated() const
+{
+ return connectionState() == Connected;
+}
+
+
+Account::ConnectionState
+ZeroconfAccount::connectionState() const
+{
+ if ( m_sipPlugin.isNull() )
+ return Disconnected;
+
+ // TODO can we get called before sipPlugin()?
+ return static_cast< ZeroconfPlugin* >( m_sipPlugin.data() )->connectionState();
+}
+
+
+SipPlugin*
+ZeroconfAccount::sipPlugin()
+{
+ if ( m_sipPlugin.isNull() )
+ m_sipPlugin = QWeakPointer< SipPlugin >( new ZeroconfPlugin( this ) );
+
+ return m_sipPlugin.data();
+}
+
+
+Q_EXPORT_PLUGIN2( Tomahawk::Accounts::AccountFactory, Tomahawk::Accounts::ZeroconfFactory )
\ No newline at end of file
diff --git a/src/accounts/zeroconf/zeroconfaccount.h b/src/accounts/zeroconf/zeroconfaccount.h
new file mode 100644
index 000000000..29a6673fd
--- /dev/null
+++ b/src/accounts/zeroconf/zeroconfaccount.h
@@ -0,0 +1,80 @@
+/* === This file is part of Tomahawk Player - ===
+ *
+ * Copyright 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 ZEROCONF_ACCOUNTS_H
+#define ZEROCONF_ACCOUNTS_H
+
+#include "accounts/Account.h"
+#include "../accountdllmacro.h"
+
+class SipPlugin;
+
+namespace Tomahawk
+{
+namespace Accounts
+{
+
+class ACCOUNTDLLEXPORT ZeroconfFactory : public AccountFactory
+{
+ Q_OBJECT
+ Q_INTERFACES( Tomahawk::Accounts::AccountFactory )
+public:
+ ZeroconfFactory();
+ virtual ~ZeroconfFactory();
+
+ virtual QString factoryId() const { return "zeroconfaccount"; }
+ virtual QString prettyName() const { return "Local Network"; }
+ QString description() const { return tr( "Automatically connect to Tomahawks on the local network" ); }
+ virtual bool isUnique() const { return true; }
+ AccountTypes types() const { return AccountTypes( SipType ); };
+#ifndef ENABLE_HEADLESS
+virtual QPixmap icon() const;
+#endif
+
+
+ virtual Account* createAccount ( const QString& pluginId = QString() );
+};
+
+class ACCOUNTDLLEXPORT ZeroconfAccount : public Account
+{
+ Q_OBJECT
+public:
+ ZeroconfAccount( const QString &accountId );
+ virtual ~ZeroconfAccount();
+
+ QPixmap icon() const;
+
+ void authenticate();
+ void deauthenticate();
+ bool isAuthenticated() const;
+ ConnectionState connectionState() const;
+
+ Tomahawk::InfoSystem::InfoPlugin* infoPlugin() { return 0; }
+ SipPlugin* sipPlugin();
+
+ QWidget* configurationWidget() { return 0; }
+ QWidget* aclWidget() { return 0; }
+
+private:
+ QWeakPointer< SipPlugin > m_sipPlugin;
+};
+
+}
+}
+
+#endif
diff --git a/src/config.h.in b/src/config.h.in
index 42e6a346b..0cdbb948e 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -20,6 +20,5 @@
#cmakedefine LIBLASTFM_FOUND
#cmakedefine GLOOX_FOUND
#cmakedefine QCA2_FOUND
-#cmakedefine LIBATTICA_FOUND
#endif // CONFIG_H_IN
diff --git a/src/configdelegatebase.cpp b/src/configdelegatebase.cpp
deleted file mode 100644
index ce6f2baae..000000000
--- a/src/configdelegatebase.cpp
+++ /dev/null
@@ -1,120 +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 "configdelegatebase.h"
-
-#include
-#include
-#include
-
-#include "utils/tomahawkutils.h"
-#include "utils/logger.h"
-
-ConfigDelegateBase::ConfigDelegateBase ( QObject* parent )
- : QStyledItemDelegate ( parent )
-{
-
-}
-
-
-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() );
-}
-
-void
-ConfigDelegateBase::drawCheckBox( QStyleOptionViewItemV4& opt, QPainter* p, const QWidget* w ) const
-{
- QStyle* style = w ? w->style() : QApplication::style();
- opt.checkState == Qt::Checked ? opt.state |= QStyle::State_On : opt.state |= QStyle::State_Off;
- style->drawPrimitive( QStyle::PE_IndicatorViewItemCheck, &opt, p, w );
-}
-
-
-void
-ConfigDelegateBase::drawConfigWrench ( QPainter* painter, QStyleOptionViewItemV4& opt, QStyleOptionToolButton& topt ) const
-{
- const QWidget* w = opt.widget;
- QStyle* style = w ? w->style() : QApplication::style();
-
- // 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.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 );
-}
-
-bool
-ConfigDelegateBase::editorEvent ( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index )
-{
- QStyleOptionViewItemV4 viewOpt( option );
- initStyleOption( &viewOpt, index );
-
- if( event->type() == QEvent::MouseButtonRelease || event->type() == QEvent::MouseButtonDblClick ) {
- m_configPressed = QModelIndex();
-
- QMouseEvent* me = static_cast< QMouseEvent* >( event );
- if( me->button() != Qt::LeftButton || !checkRectForIndex( option, index ).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( 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 );
- if( me->button() == Qt::LeftButton && configRectForIndex( option, index ).contains( me->pos() ) ) {
- m_configPressed = index;
-
- emit configPressed( index );
- return true;
- }
- }
-
- return QStyledItemDelegate::editorEvent( event, model, option, index );
-}
diff --git a/src/configdelegatebase.h b/src/configdelegatebase.h
index d86baad1a..bce0581c9 100644
--- a/src/configdelegatebase.h
+++ b/src/configdelegatebase.h
@@ -36,16 +36,15 @@ 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 );
protected:
- void drawCheckBox( QStyleOptionViewItemV4& opt, QPainter* p, const QWidget* w ) const;
- void drawConfigWrench( QPainter* painter, QStyleOptionViewItemV4& option, QStyleOptionToolButton& topt ) const;
private:
QModelIndex m_configPressed;
diff --git a/src/delegateconfigwrapper.h b/src/delegateconfigwrapper.h
index ef737b33b..4a2d4bfd1 100644
--- a/src/delegateconfigwrapper.h
+++ b/src/delegateconfigwrapper.h
@@ -22,28 +22,28 @@
#include
#include
#include
+#include
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
m_widget->setVisible( true );
#endif
-
setWindowTitle( title );
QVBoxLayout* v = new QVBoxLayout( this );
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 );
@@ -59,6 +59,17 @@ public:
#endif
}
+
+ ~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 )
{
@@ -75,6 +86,12 @@ 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 closedWithDelete();
+ reject();
+ }
else
done( QDialog::Rejected );
}
@@ -97,9 +114,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/diagnosticsdialog.cpp b/src/diagnosticsdialog.cpp
index 050c435a6..cc77abab5 100644
--- a/src/diagnosticsdialog.cpp
+++ b/src/diagnosticsdialog.cpp
@@ -90,81 +90,81 @@ void DiagnosticsDialog::updateLogView()
log.append("\n\n");
- // Peers
- log.append("SIP PLUGINS:\n");
- QList< Tomahawk::source_ptr > sources = SourceList::instance()->sources( true );
- Q_FOREACH(SipPlugin *sip, SipHandler::instance()->allPlugins())
- {
- Q_ASSERT(sip);
- QString stateString;
- switch( sip->connectionState() )
- {
- case SipPlugin::Connecting:
- stateString = "Connecting";
- break;
+ // Peers / Accounts, TODO
+ log.append("ACCOUNTS:\n");
+// QList< Tomahawk::source_ptr > sources = SourceList::instance()->sources( true );
+// Q_FOREACH(SipPlugin *sip, SipHandler::instance()->allPlugins())
+// {
+// Q_ASSERT(sip);
+// QString stateString;
+// switch( sip->connectionState() )
+// {
+// case SipPlugin::Connecting:
+// stateString = "Connecting";
+// break;
+//
+// case SipPlugin::Connected:
+// stateString = "Connected";
+// break;
+//
+// case SipPlugin::Disconnected:
+// stateString = "Disconnected";
+// break;
+// case SipPlugin::Disconnecting:
+// stateString = "Disconnecting";
+// }
+// log.append(
+// QString(" %2 (%1): %3 (%4)\n")
+// .arg(sip->account()->accountServiceName())
+// .arg(sip->friendlyName())
+// .arg(sip->account()->accountFriendlyName())
+// .arg(stateString)
+// );
- case SipPlugin::Connected:
- stateString = "Connected";
- break;
-
- case SipPlugin::Disconnected:
- stateString = "Disconnected";
- break;
- case SipPlugin::Disconnecting:
- stateString = "Disconnecting";
- }
- log.append(
- QString(" %2 (%1): %3 (%4)\n")
- .arg(sip->name())
- .arg(sip->friendlyName())
- .arg(sip->accountName())
- .arg(stateString)
- );
-
- Q_FOREACH( const QString &peerId, sip->peersOnline() )
- {
- /* enable this again, when we check the source has this peerId
- bool connected = false;
- Q_FOREACH( const Tomahawk::source_ptr &source, sources )
- {
- if( source->controlConnection() )
- {
- connected = true;
- break;
- }
- }*/
-
- QString versionString = SipHandler::instance()->versionString( peerId );
- SipInfo sipInfo = SipHandler::instance()->sipInfo( peerId );
- if( !sipInfo.isValid() )
- log.append(
- QString(" %1: %2 %3" /*"(%4)"*/ "\n")
- .arg( peerId )
- .arg( "sipinfo invalid" )
- .arg( versionString )
- // .arg( connected ? "connected" : "not connected")
- );
- else if( sipInfo.isVisible() )
- log.append(
- QString(" %1: %2:%3 %4" /*" (%5)"*/ "\n")
- .arg( peerId )
- .arg( sipInfo.host().hostName() )
- .arg( sipInfo.port() )
- .arg( versionString )
- // .arg( connected ? "connected" : "not connected")
-
- );
- else
- log.append(
- QString(" %1: visible: false %2" /*" (%3)"*/ "\n")
- .arg( peerId )
- .arg( versionString )
- // .arg( connected ? "connected" : "not connected")
-
- );
- }
- log.append("\n");
- }
+// Q_FOREACH( const QString &peerId, sip->peersOnline() )
+// {
+// /* enable this again, when we check the source has this peerId
+// bool connected = false;
+// Q_FOREACH( const Tomahawk::source_ptr &source, sources )
+// {
+// if( source->controlConnection() )
+// {
+// connected = true;
+// break;
+// }
+// }*/
+//
+// QString versionString = SipHandler::instance()->versionString( peerId );
+// SipInfo sipInfo = SipHandler::instance()->sipInfo( peerId );
+// if( !sipInfo.isValid() )
+// log.append(
+// QString(" %1: %2 %3" /*"(%4)"*/ "\n")
+// .arg( peerId )
+// .arg( "sipinfo invalid" )
+// .arg( versionString )
+// // .arg( connected ? "connected" : "not connected")
+// );
+// else if( sipInfo.isVisible() )
+// log.append(
+// QString(" %1: %2:%3 %4" /*" (%5)"*/ "\n")
+// .arg( peerId )
+// .arg( sipInfo.host().hostName() )
+// .arg( sipInfo.port() )
+// .arg( versionString )
+// // .arg( connected ? "connected" : "not connected")
+//
+// );
+// else
+// log.append(
+// QString(" %1: visible: false %2" /*" (%3)"*/ "\n")
+// .arg( peerId )
+// .arg( versionString )
+// // .arg( connected ? "connected" : "not connected")
+//
+// );
+// }
+// log.append("\n");
+// }
ui->logView->setPlainText(log);
}
diff --git a/src/libtomahawk/AtticaManager.cpp b/src/libtomahawk/AtticaManager.cpp
index 1fe452142..2ecbc6fe3 100644
--- a/src/libtomahawk/AtticaManager.cpp
+++ b/src/libtomahawk/AtticaManager.cpp
@@ -32,6 +32,8 @@
#include
#include "utils/logger.h"
+#include "accounts/ResolverAccount.h"
+#include "accounts/AccountManager.h"
using namespace Attica;
@@ -133,6 +135,20 @@ AtticaManager::resolvers() const
}
+Content
+AtticaManager::resolverForId( const QString& id ) const
+{
+ foreach ( const Attica::Content& c, m_resolvers )
+ {
+ if ( c.id() == id )
+ return c;
+ }
+
+ return Content();
+}
+
+
+
AtticaManager::ResolverState
AtticaManager::resolverState ( const Content& resolver ) const
{
@@ -196,6 +212,38 @@ AtticaManager::userHasRated( const Content& c ) const
}
+bool
+AtticaManager::hasCustomAccountForAttica( const QString &id ) const
+{
+ // Only last.fm at the moment contains a custom account
+ if ( id == "lastfm" )
+ return true;
+
+ return false;
+}
+
+
+Tomahawk::Accounts::Account*
+AtticaManager::customAccountForAttica( const QString &id ) const
+{
+ return m_customAccounts.value( id );
+}
+
+
+void
+AtticaManager::registerCustomAccount( const QString &atticaId, Tomahawk::Accounts::Account *account )
+{
+ m_customAccounts.insert( atticaId, account );
+}
+
+
+AtticaManager::Resolver
+AtticaManager::resolverData(const QString &atticaId) const
+{
+ return m_resolverStates.value( atticaId );
+}
+
+
void
AtticaManager::providerAdded( const Provider& provider )
{
@@ -218,6 +266,24 @@ AtticaManager::resolversList( BaseJob* j )
m_resolvers = job->itemList();
m_resolverStates = TomahawkSettingsGui::instanceGui()->atticaResolverStates();
+ // Sanity check. if any resolvers are installed that don't exist on the hd, remove them.
+ foreach ( const QString& rId, m_resolverStates.keys() )
+ {
+ if ( m_resolverStates[ rId ].state == Installed ||
+ m_resolverStates[ rId ].state == NeedsUpgrade )
+ {
+ // Guess location on disk
+ QDir dir( QString( "%1/atticaresolvers/%2" ).arg( TomahawkUtils::appDataDir().absolutePath() ).arg( rId ) );
+ if ( !dir.exists() )
+ {
+ // Uh oh
+ qWarning() << "Found attica resolver marked as installed that didn't exist on disk! Setting to uninstalled: " << rId << dir.absolutePath();
+ m_resolverStates[ rId ].state = Uninstalled;
+ TomahawkSettingsGui::instanceGui()->setAtticaResolverState( rId, Uninstalled );
+ }
+ }
+ }
+
// load icon cache from disk, and fetch any we are missing
loadPixmapsFromCache();
@@ -236,6 +302,8 @@ AtticaManager::resolversList( BaseJob* j )
}
syncServerData();
+
+ emit resolversLoaded( m_resolvers );
}
@@ -299,7 +367,7 @@ AtticaManager::syncServerData()
void
-AtticaManager::installResolver( const Content& resolver, bool autoEnable )
+AtticaManager::installResolver( const Content& resolver, bool autoCreateAccount )
{
Q_ASSERT( !resolver.id().isNull() );
@@ -313,7 +381,7 @@ AtticaManager::installResolver( const Content& resolver, bool autoEnable )
ItemJob< DownloadItem >* job = m_resolverProvider.downloadLink( resolver.id() );
connect( job, SIGNAL( finished( Attica::BaseJob* ) ), this, SLOT( resolverDownloadFinished( Attica::BaseJob* ) ) );
job->setProperty( "resolverId", resolver.id() );
- job->setProperty( "autoEnable", autoEnable );
+ job->setProperty( "createAccount", autoCreateAccount );
job->start();
}
@@ -328,12 +396,11 @@ AtticaManager::upgradeResolver( const Content& resolver )
if ( !m_resolverStates.contains( resolver.id() ) || m_resolverStates[ resolver.id() ].state != NeedsUpgrade )
return;
- const bool enabled = TomahawkSettings::instance()->enabledScriptResolvers().contains( m_resolverStates[ resolver.id() ].scriptPath );
m_resolverStates[ resolver.id() ].state = Upgrading;
emit resolverStateChanged( resolver.id() );
uninstallResolver( resolver );
- installResolver( resolver, enabled );
+ installResolver( resolver, false );
}
@@ -350,7 +417,7 @@ AtticaManager::resolverDownloadFinished ( BaseJob* j )
QNetworkReply* reply = TomahawkUtils::nam()->get( QNetworkRequest( url ) );
connect( reply, SIGNAL( finished() ), this, SLOT( payloadFetched() ) );
reply->setProperty( "resolverId", job->property( "resolverId" ) );
- reply->setProperty( "autoEnable", job->property( "autoEnable" ) );
+ reply->setProperty( "createAccount", job->property( "createAccount" ) );
}
else
{
@@ -386,10 +453,14 @@ AtticaManager::payloadFetched()
// update with absolute, not relative, path
m_resolverStates[ resolverId ].scriptPath = resolverPath;
- const bool autoEnable = reply->property( "autoEnable" ).toBool();
+ if ( reply->property( "createAccount" ).toBool() )
+ {
+ // Do the install / add to tomahawk
+ Tomahawk::Accounts::Account* resolver = Tomahawk::Accounts::ResolverAccountFactory::createFromPath( resolverPath, true );
+ Tomahawk::Accounts::AccountManager::instance()->addAccount( resolver );
+ TomahawkSettings::instance()->addAccount( resolver->accountId() );
+ }
- // Do the install / add to tomahawk
- Tomahawk::Pipeline::instance()->addScriptResolver( resolverPath, autoEnable );
m_resolverStates[ resolverId ].state = Installed;
TomahawkSettingsGui::instanceGui()->setAtticaResolverStates( m_resolverStates );
emit resolverInstalled( resolverId );
@@ -475,6 +546,9 @@ AtticaManager::extractPayload( const QString& filename, const QString& resolverI
void
AtticaManager::uninstallResolver( const QString& pathToResolver )
{
+ // when is this used? find and fix
+ Q_ASSERT(false);
+
// User manually removed a resolver not through attica dialog, simple remove
QRegExp r( ".*([^/]*)/contents/code/main.js" );
r.indexIn( pathToResolver );
@@ -506,9 +580,21 @@ AtticaManager::uninstallResolver( const Content& resolver )
m_resolverStates[ resolver.id() ].state = Uninstalled;
TomahawkSettingsGui::instanceGui()->setAtticaResolverState( resolver.id(), Uninstalled );
+
+ // remove account as well
+ QList< Tomahawk::Accounts::Account* > accounts = Tomahawk::Accounts::AccountManager::instance()->accounts( Tomahawk::Accounts::ResolverType );
+ foreach ( Tomahawk::Accounts::Account* account, accounts )
+ {
+ if ( Tomahawk::Accounts::AtticaResolverAccount* atticaAccount = qobject_cast< Tomahawk::Accounts::AtticaResolverAccount* >( account ) )
+ {
+ if ( atticaAccount->atticaId() == resolver.id() ) // this is the account we want to remove
+ {
+ Tomahawk::Accounts::AccountManager::instance()->removeAccount( atticaAccount );
+ }
+ }
+ }
}
- Tomahawk::Pipeline::instance()->removeScriptResolver( pathFromId( resolver.id() ) );
doResolverRemove( resolver.id() );
}
diff --git a/src/libtomahawk/AtticaManager.h b/src/libtomahawk/AtticaManager.h
index 5c302ddda..09b441dd5 100644
--- a/src/libtomahawk/AtticaManager.h
+++ b/src/libtomahawk/AtticaManager.h
@@ -26,12 +26,12 @@
#include
#include "dllmacro.h"
+#include "accounts/Account.h"
-#ifdef LIBATTICA_FOUND
#include
#include
#include
-#endif
+
class DLLEXPORT AtticaManager : public QObject
{
@@ -71,18 +71,13 @@ public:
}
explicit AtticaManager ( QObject* parent = 0 );
-#ifdef LIBATTICA_FOUND
-
virtual ~AtticaManager();
-#else
- virtual ~AtticaManager() {}
-#endif
-
-#ifdef LIBATTICA_FOUND
bool resolversLoaded() const;
Attica::Content::List resolvers() const;
+ Attica::Content resolverForId( const QString& id ) const;
+
ResolverState resolverState( const Attica::Content& resolver ) const;
QPixmap iconForResolver( const Attica::Content& id ); // Looks up in icon cache
@@ -93,12 +88,22 @@ public:
void uploadRating( const Attica::Content& c );
bool userHasRated( const Attica::Content& c ) const;
+ /**
+ If the resolver coming from libattica has a native custom c++ account
+ as well. For example the last.fm account.
+ */
+ bool hasCustomAccountForAttica( const QString& id ) const;
+ Tomahawk::Accounts::Account* customAccountForAttica( const QString& id ) const;
+ void registerCustomAccount( const QString& atticaId, Tomahawk::Accounts::Account* account );
+
+ AtticaManager::Resolver resolverData( const QString& atticaId ) const;
+
public slots:
- void installResolver( const Attica::Content& resolver, bool autoEnable = true );
+ void installResolver( const Attica::Content& resolver, bool autoCreateAccount = true );
void upgradeResolver( const Attica::Content& resolver );
signals:
- void resolversReloaded( const Attica::Content::List& resolvers );
+ void resolversLoaded( const Attica::Content::List& resolvers );
void resolverStateChanged( const QString& resolverId );
void resolverInstalled( const QString& resolverId );
@@ -125,13 +130,25 @@ private:
Attica::Provider m_resolverProvider;
Attica::Content::List m_resolvers;
StateHash m_resolverStates;
-#endif
+
+ QMap< QString, Tomahawk::Accounts::Account* > m_customAccounts;
static AtticaManager* s_instance;
};
-#ifdef LIBATTICA_FOUND
+class DLLEXPORT CustomAtticaAccount : public Tomahawk::Accounts::Account
+{
+ Q_OBJECT
+public:
+ virtual ~CustomAtticaAccount() {}
+
+ virtual Attica::Content atticaContent() const = 0;
+
+protected:
+ // No, you can't.
+ CustomAtticaAccount( const QString& id ) : Tomahawk::Accounts::Account( id ) {}
+};
+
Q_DECLARE_METATYPE( Attica::Content );
-#endif
#endif // ATTICAMANAGER_H
diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt
index 55fbc8da8..36fc583ae 100644
--- a/src/libtomahawk/CMakeLists.txt
+++ b/src/libtomahawk/CMakeLists.txt
@@ -102,8 +102,6 @@ set( libGuiSources
resolvers/scriptresolver.cpp
resolvers/qtscriptresolver.cpp
- sip/SipModel.cpp
-
utils/widgetdragfilter.cpp
utils/xspfgenerator.cpp
utils/jspfloader.cpp
@@ -229,8 +227,6 @@ set( libGuiHeaders
resolvers/scriptresolver.h
resolvers/qtscriptresolver.h
- sip/SipModel.h
-
utils/widgetdragfilter.h
utils/xspfgenerator.h
utils/jspfloader.h
@@ -311,6 +307,14 @@ set( libSources
EchonestCatalogSynchronizer.cpp
+ accounts/AccountManager.cpp
+ accounts/Account.cpp
+ accounts/AccountModel.cpp
+ accounts/AccountModelFilterProxy.cpp
+ accounts/ResolverAccount.cpp
+ accounts/LastFmAccount.cpp
+ accounts/LastFmConfig.cpp
+
sip/SipPlugin.cpp
sip/SipHandler.cpp
sip/sipinfo.cpp
@@ -445,9 +449,16 @@ set( libHeaders
albumplaylistinterface.h
playlist.h
playlistplaylistinterface.h
-
viewpage.h
+ accounts/Account.h
+ accounts/AccountManager.h
+ accounts/AccountModel.h
+ accounts/AccountModelFilterProxy.h
+ accounts/ResolverAccount.h
+ accounts/LastFmAccount.h
+ accounts/LastFmConfig.h
+
EchonestCatalogSynchronizer.h
sip/SipPlugin.h
@@ -548,6 +559,10 @@ set( libHeaders
)
set( libHeaders_NoMOC
+ viewpage.h
+
+ accounts/Account.h
+
infosystem/infoplugins/unix/imageconverter.h
taghandlers/tag.h
@@ -575,6 +590,7 @@ set( libUI ${libUI}
playlist/queueview.ui
context/ContextWidget.ui
infobar/infobar.ui
+ accounts/LastFmConfig.ui
)
include_directories( . ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/.. ..
diff --git a/src/libtomahawk/ExternalResolver.h b/src/libtomahawk/ExternalResolver.h
index a63f42396..bf3a01082 100644
--- a/src/libtomahawk/ExternalResolver.h
+++ b/src/libtomahawk/ExternalResolver.h
@@ -1,6 +1,7 @@
/* === This file is part of Tomahawk Player - ===
*
* Copyright 2010-2011, Christian Muehlhaeuser
+ * 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
@@ -24,6 +25,7 @@
#include "dllmacro.h"
#include "resolver.h"
+#include
#include
@@ -64,7 +66,7 @@ public slots:
virtual void stop() = 0;
signals:
- void changed(); // if config widget was added/removed
+ void changed(); // if config widget was added/removed, name changed, etc
protected:
void setFilePath( const QString& path ) { m_filePath = path; }
diff --git a/src/libtomahawk/TomahawkSettingsGui.cpp b/src/libtomahawk/TomahawkSettingsGui.cpp
index b9b95bfc1..32f70a4b8 100644
--- a/src/libtomahawk/TomahawkSettingsGui.cpp
+++ b/src/libtomahawk/TomahawkSettingsGui.cpp
@@ -21,53 +21,8 @@
#include
#include "settingsdialog.h"
-// #include
-//
-// #include "sip/SipHandler.h"
-// #include "playlistinterface.h"
-//
-// #include "utils/logger.h"
-// #include "utils/tomahawkutils.h"
-//
-// #include "database/databasecommand_updatesearchindex.h"
-// #include "database/database.h"
-
-#define VERSION 5
-
using namespace Tomahawk;
-inline QDataStream& operator<<(QDataStream& out, const AtticaManager::StateHash& states)
-{
- out << VERSION;
- out << (quint32)states.count();
- foreach( const QString& key, states.keys() )
- {
- AtticaManager::Resolver resolver = states[ key ];
- out << key << resolver.version << resolver.scriptPath << (qint32)resolver.state << resolver.userRating;
- }
- return out;
-}
-
-
-inline QDataStream& operator>>(QDataStream& in, AtticaManager::StateHash& states)
-{
- quint32 count = 0, version = 0;
- in >> version;
- in >> count;
- for ( uint i = 0; i < count; i++ )
- {
- QString key, version, scriptPath;
- qint32 state, userRating;
- in >> key;
- in >> version;
- in >> scriptPath;
- in >> state;
- in >> userRating;
- states[ key ] = AtticaManager::Resolver( version, scriptPath, userRating, (AtticaManager::ResolverState)state );
- }
- return in;
-}
-
TomahawkSettingsGui*
TomahawkSettingsGui::instanceGui()
{
@@ -78,8 +33,6 @@ TomahawkSettingsGui::instanceGui()
TomahawkSettingsGui::TomahawkSettingsGui( QObject* parent )
: TomahawkSettings( parent )
{
- qRegisterMetaType< AtticaManager::StateHash >( "AtticaManager::StateHash" );
- qRegisterMetaTypeStreamOperators("AtticaManager::StateHash");
}
diff --git a/src/libtomahawk/accounts/Account.cpp b/src/libtomahawk/accounts/Account.cpp
new file mode 100644
index 000000000..208cc7bac
--- /dev/null
+++ b/src/libtomahawk/accounts/Account.cpp
@@ -0,0 +1,211 @@
+/* === This file is part of Tomahawk Player - ===
+ *
+ * Copyright 2011, Christian Muehlhaeuser
+ * Copyright 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 "Account.h"
+
+namespace Tomahawk
+{
+
+namespace Accounts
+{
+
+QString
+accountTypeToString( AccountType type )
+{
+ switch ( type )
+ {
+ case SipType:
+ return QObject::tr( "Friend Finders" );
+ case ResolverType:
+ return QObject::tr( "Music Finders" );
+ case InfoType:
+ case StatusPushType:
+ return QObject::tr( "Status Updaters" );
+ }
+
+ return QString();
+}
+
+
+Account::Account( const QString& accountId )
+ : QObject()
+ , m_enabled( false )
+ , m_autoConnect( false )
+ , m_accountId( accountId )
+{
+ connect( this, SIGNAL( error( int, QString ) ), this, SLOT( onError( int,QString ) ) );
+ connect( this, SIGNAL( connectionStateChanged( Tomahawk::Accounts::Account::ConnectionState ) ) , this, SLOT( onConnectionStateChanged( Tomahawk::Accounts::Account::ConnectionState ) ) );
+
+ loadFromConfig( accountId );
+}
+
+
+Account::~Account()
+{
+ sync();
+}
+
+
+QWidget*
+Account::configurationWidget()
+{
+ return 0;
+}
+
+
+QWidget*
+Account::aclWidget()
+{
+ return 0;
+}
+
+
+QPixmap
+Account::icon() const
+{
+ return QPixmap();
+}
+
+void
+Account::authenticate()
+{
+ return;
+}
+
+
+void
+Account::deauthenticate()
+{
+ return;
+}
+
+
+bool
+Account::isAuthenticated() const
+{
+ return false;
+}
+
+
+void
+Account::onError( int errorCode, const QString& error )
+{
+ Q_UNUSED( errorCode );
+
+ QMutexLocker locker( &m_mutex );
+ m_cachedError = error;
+}
+
+
+void
+Account::onConnectionStateChanged( Account::ConnectionState )
+{
+ m_cachedError.clear();
+}
+
+
+void
+Account::syncConfig()
+{
+ TomahawkSettings* s = TomahawkSettings::instance();
+ s->beginGroup( "accounts/" + m_accountId );
+ s->setValue( "accountfriendlyname", m_accountFriendlyName );
+ s->setValue( "enabled", m_enabled );
+ s->setValue( "autoconnect", m_autoConnect );
+ s->setValue( "credentials", m_credentials );
+ s->setValue( "configuration", m_configuration );
+ s->setValue( "acl", m_acl );
+ s->setValue( "types", m_types );
+ s->endGroup();
+ s->sync();
+}
+
+
+void
+Account::loadFromConfig( const QString& accountId )
+{
+ m_accountId = accountId;
+ TomahawkSettings* s = TomahawkSettings::instance();
+ s->beginGroup( "accounts/" + m_accountId );
+ m_accountFriendlyName = s->value( "accountfriendlyname", QString() ).toString();
+ m_enabled = s->value( "enabled", false ).toBool();
+ m_autoConnect = s->value( "autoconnect", false ).toBool();
+ m_credentials = s->value( "credentials", QVariantHash() ).toHash();
+ m_configuration = s->value( "configuration", QVariantHash() ).toHash();
+ m_acl = s->value( "acl", QVariantMap() ).toMap();
+ m_types = s->value( "types", QStringList() ).toStringList();
+ s->endGroup();
+}
+
+
+void
+Account::removeFromConfig()
+{
+ TomahawkSettings* s = TomahawkSettings::instance();
+ s->beginGroup( "accounts/" + m_accountId );
+ s->remove( "accountfriendlyname" );
+ s->remove( "enabled" );
+ s->remove( "autoconnect" );
+ s->remove( "credentials" );
+ s->remove( "configuration" );
+ s->remove( "acl" );
+ s->remove( "types" );
+ s->endGroup();
+ s->remove( "accounts/" + m_accountId );
+}
+
+
+void
+Account::setTypes( AccountTypes types )
+{
+ QMutexLocker locker( &m_mutex );
+ m_types = QStringList();
+ if ( types & InfoType )
+ m_types << "InfoType";
+ if ( types & SipType )
+ m_types << "SipType";
+ if ( types & ResolverType )
+ m_types << "ResolverType";
+ if ( types & StatusPushType )
+ m_types << "StatusPushType";
+ syncConfig();
+}
+
+
+AccountTypes
+Account::types() const
+{
+ QMutexLocker locker( &m_mutex );
+ AccountTypes types;
+ if ( m_types.contains( "InfoType" ) )
+ types |= InfoType;
+ if ( m_types.contains( "SipType" ) )
+ types |= SipType;
+ if ( m_types.contains( "ResolverType" ) )
+ types |= ResolverType;
+ if ( m_types.contains( "StatusPushType" ) )
+ types |= StatusPushType;
+
+ return types;
+}
+
+
+}
+
+}
\ No newline at end of file
diff --git a/src/libtomahawk/accounts/Account.h b/src/libtomahawk/accounts/Account.h
new file mode 100644
index 000000000..73a7dedee
--- /dev/null
+++ b/src/libtomahawk/accounts/Account.h
@@ -0,0 +1,193 @@
+/* === This file is part of Tomahawk Player - ===
+ *
+ * Copyright 2011, Christian Muehlhaeuser
+ * Copyright 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 ACCOUNT_H
+#define ACCOUNT_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "typedefs.h"
+#include "dllmacro.h"
+#include "tomahawksettings.h"
+
+class SipPlugin;
+
+namespace Tomahawk
+{
+
+namespace InfoSystem
+{
+ class InfoPlugin;
+}
+
+namespace Accounts
+{
+
+enum AccountType
+{
+ NoType = 0x00,
+
+ InfoType = 0x01,
+ SipType = 0x02,
+ ResolverType = 0x04,
+ StatusPushType = 0x08
+};
+
+DLLEXPORT QString accountTypeToString( AccountType type );
+
+Q_DECLARE_FLAGS(AccountTypes, AccountType);
+
+inline QString generateId( const QString &factoryId )
+{
+ QString uniq = QUuid::createUuid().toString().mid( 1, 8 );
+ return factoryId + "_" + uniq;
+}
+
+class DLLEXPORT Account : public QObject
+{
+ Q_OBJECT
+
+public:
+ enum AuthErrorCode { AuthError, ConnectionError };
+ enum ConnectionState { Disconnected, Connecting, Connected, Disconnecting };
+
+ explicit Account( const QString &accountId );
+ virtual ~Account();
+
+ QString accountServiceName() const { QMutexLocker locker( &m_mutex ); return m_accountServiceName; } // e.g. "Twitter", "Last.fm"
+ QString accountFriendlyName() const { QMutexLocker locker( &m_mutex ); return m_accountFriendlyName; } // e.g. screen name on the service, JID, etc.
+ bool enabled() const { QMutexLocker locker( &m_mutex ); return m_enabled; }
+ bool autoConnect() const { QMutexLocker locker( &m_mutex ); return m_autoConnect; }
+ QString accountId() const { QMutexLocker locker( &m_mutex ); return m_accountId; }
+
+ QVariantHash configuration() const { QMutexLocker locker( &m_mutex ); return m_configuration; }
+
+ /**
+ * Configuration widgets can have a "dataError( bool )" signal to enable/disable the OK button in their wrapper dialogs.
+ */
+ virtual QWidget* configurationWidget() = 0;
+ virtual void saveConfig() {} // called when the widget has been edited. save values from config widget, call sync() to write to disk account generic settings
+
+ QVariantHash credentials() const { QMutexLocker locker( &m_mutex ); return m_credentials; }
+
+ QVariantMap acl() const { QMutexLocker locker( &m_mutex ); return m_acl; }
+ virtual QWidget* aclWidget() = 0;
+
+ virtual QPixmap icon() const = 0;
+
+ virtual ConnectionState connectionState() const = 0;
+ virtual bool isAuthenticated() const = 0;
+
+ virtual QString errorMessage() const { QMutexLocker locker( &m_mutex ); return m_cachedError; }
+
+ virtual Tomahawk::InfoSystem::InfoPlugin* infoPlugin() = 0;
+ virtual SipPlugin* sipPlugin() = 0;
+
+ AccountTypes types() const;
+
+ void setAccountServiceName( const QString &serviceName ) { QMutexLocker locker( &m_mutex ); m_accountServiceName = serviceName; }
+ void setAccountFriendlyName( const QString &friendlyName ) { QMutexLocker locker( &m_mutex ); m_accountFriendlyName = friendlyName; }
+ void setEnabled( bool enabled ) { QMutexLocker locker( &m_mutex ); m_enabled = enabled; }
+ void setAutoConnect( bool autoConnect ) { QMutexLocker locker( &m_mutex ); m_autoConnect = autoConnect; }
+ void setAccountId( const QString &accountId ) { QMutexLocker locker( &m_mutex ); m_accountId = accountId; }
+ void setCredentials( const QVariantHash &credentialHash ) { QMutexLocker locker( &m_mutex ); m_credentials = credentialHash; }
+ void setConfiguration( const QVariantHash &configuration ) { QMutexLocker locker( &m_mutex ); m_configuration = configuration; }
+ void setAcl( const QVariantMap &acl ) { QMutexLocker locker( &m_mutex ); m_acl = acl; }
+ void setTypes( AccountTypes types );
+
+ void sync() { QMutexLocker locker( &m_mutex ); syncConfig(); };
+
+ /**
+ * Removes all the settings held in the config file for this account instance
+ *
+ * Re-implement if you have saved additional files or config settings outside the built-in ones
+ */
+ virtual void removeFromConfig();
+
+public slots:
+ virtual void authenticate() = 0;
+ virtual void deauthenticate() = 0;
+
+signals:
+ void error( int errorId, const QString& errorStr );
+ void connectionStateChanged( Tomahawk::Accounts::Account::ConnectionState state );
+
+ void configurationChanged();
+
+protected:
+ virtual void loadFromConfig( const QString &accountId );
+ virtual void syncConfig();
+
+private slots:
+ void onConnectionStateChanged( Tomahawk::Accounts::Account::ConnectionState );
+ void onError( int, const QString& );
+
+private:
+ QString m_accountServiceName;
+ QString m_accountFriendlyName;
+ QString m_cachedError;
+ bool m_enabled;
+ bool m_autoConnect;
+ QString m_accountId;
+ QVariantHash m_credentials;
+ QVariantHash m_configuration;
+ QVariantMap m_acl;
+ QStringList m_types;
+ mutable QMutex m_mutex;
+};
+
+class DLLEXPORT AccountFactory : public QObject
+{
+ Q_OBJECT
+public:
+ AccountFactory() {}
+ virtual ~AccountFactory() {}
+
+ // display name for plugin
+ virtual QString prettyName() const = 0;
+ // internal name
+ virtual QString factoryId() const = 0;
+ // description to be shown when user views a list of account types
+ virtual QString description() const = 0;
+ // if the user can create multiple
+ virtual bool isUnique() const { return false; }
+
+ virtual QPixmap icon() const { return QPixmap(); }
+ virtual bool allowUserCreation() const { return true; }
+
+ // What are the supported types for accounts this factory creates?
+ virtual AccountTypes types() const = 0;
+
+ virtual Account* createAccount( const QString& accountId = QString() ) = 0;
+};
+
+};
+
+};
+
+Q_DECLARE_INTERFACE( Tomahawk::Accounts::AccountFactory, "tomahawk.AccountFactory/1.0" )
+
+Q_DECLARE_METATYPE( QList< Tomahawk::Accounts::Account* > )
+Q_DECLARE_METATYPE( Tomahawk::Accounts::AccountTypes )
+#endif
diff --git a/src/libtomahawk/accounts/AccountManager.cpp b/src/libtomahawk/accounts/AccountManager.cpp
new file mode 100644
index 000000000..bef708937
--- /dev/null
+++ b/src/libtomahawk/accounts/AccountManager.cpp
@@ -0,0 +1,410 @@
+/* === This file is part of Tomahawk Player - ===
+ *
+ * Copyright 2010-2011, Christian Muehlhaeuser
+ * 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 "AccountManager.h"
+#include "config.h"
+#include "sourcelist.h"
+#include "ResolverAccount.h"
+#include "LastFmAccount.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace Tomahawk
+{
+
+namespace Accounts
+{
+
+
+AccountManager* AccountManager::s_instance = 0;
+
+
+AccountManager*
+AccountManager::instance()
+{
+ return s_instance;
+}
+
+
+AccountManager::AccountManager( QObject *parent )
+ : QObject( parent )
+{
+ s_instance = this;
+
+ connect( TomahawkSettings::instance(), SIGNAL( changed() ), SLOT( onSettingsChanged() ) );
+
+ loadPluginFactories( findPluginFactories() );
+
+ // We include the resolver factory manually, not in a plugin
+ ResolverAccountFactory* f = new ResolverAccountFactory();
+ m_accountFactories[ f->factoryId() ] = f;
+
+ LastFmAccountFactory* l = new LastFmAccountFactory();
+ m_accountFactories[ l->factoryId() ] = l;
+}
+
+
+AccountManager::~AccountManager()
+{
+ delete SipHandler::instance();
+
+ disconnectAll();
+ qDeleteAll( m_accounts );
+}
+
+
+QStringList
+AccountManager::findPluginFactories()
+{
+ QStringList paths;
+ QList< QDir > pluginDirs;
+
+ QDir appDir( qApp->applicationDirPath() );
+#ifdef Q_WS_MAC
+ if ( appDir.dirName() == "MacOS" )
+ {
+ // Development convenience-hack
+ appDir.cdUp();
+ appDir.cdUp();
+ appDir.cdUp();
+ }
+#endif
+
+ QDir libDir( CMAKE_INSTALL_PREFIX "/lib" );
+
+ QDir lib64Dir( appDir );
+ lib64Dir.cdUp();
+ lib64Dir.cd( "lib64" );
+
+ pluginDirs << appDir << libDir << lib64Dir << QDir( qApp->applicationDirPath() );
+ foreach ( const QDir& pluginDir, pluginDirs )
+ {
+ tDebug() << Q_FUNC_INFO << "Checking directory for plugins:" << pluginDir;
+ foreach ( QString fileName, pluginDir.entryList( QStringList() << "*tomahawk_account_*.so" << "*tomahawk_account_*.dylib" << "*tomahawk_account_*.dll", QDir::Files ) )
+ {
+ if ( fileName.startsWith( "libtomahawk_account" ) )
+ {
+ const QString path = pluginDir.absoluteFilePath( fileName );
+ if ( !paths.contains( path ) )
+ paths << path;
+ }
+ }
+ }
+
+ return paths;
+}
+
+
+void
+AccountManager::loadPluginFactories( const QStringList& paths )
+{
+ foreach ( QString fileName, paths )
+ {
+ if ( !QLibrary::isLibrary( fileName ) )
+ continue;
+
+ tDebug() << Q_FUNC_INFO << "Trying to load plugin:" << fileName;
+ loadPluginFactory( fileName );
+ }
+}
+
+
+bool
+AccountManager::hasPluginWithFactory( const QString& factory ) const
+{
+ foreach( Account* account, m_accounts ) {
+ if( factoryFromId( account->accountId() ) == factory )
+ return true;
+ }
+ return false;
+
+}
+
+
+QString
+AccountManager::factoryFromId( const QString& accountId ) const
+{
+ return accountId.split( "_" ).first();
+}
+
+AccountFactory*
+AccountManager::factoryForAccount( Account* account ) const
+{
+ const QString factoryId = factoryFromId( account->accountId() );
+ return m_accountFactories.value( factoryId, 0 );
+}
+
+
+void
+AccountManager::loadPluginFactory( const QString& path )
+{
+ QPluginLoader loader( path );
+ QObject* plugin = loader.instance();
+ if ( !plugin )
+ {
+ tDebug() << Q_FUNC_INFO << "Error loading plugin:" << loader.errorString();
+ }
+
+ AccountFactory* accountfactory = qobject_cast( plugin );
+ if ( accountfactory )
+ {
+ tDebug() << Q_FUNC_INFO << "Loaded plugin factory:" << loader.fileName() << accountfactory->factoryId() << accountfactory->prettyName();
+ m_accountFactories[ accountfactory->factoryId() ] = accountfactory;
+ } else
+ {
+ tDebug() << Q_FUNC_INFO << "Loaded invalid plugin.." << loader.fileName();
+ }
+}
+
+
+
+void
+AccountManager::enableAccount( Account* account )
+{
+ if ( account->isAuthenticated() )
+ return;
+
+ account->authenticate();
+
+ account->setEnabled( true );
+ m_enabledAccounts << account;
+
+ account->sync();
+}
+
+
+void
+AccountManager::disableAccount( Account* account )
+{
+ if ( !account->isAuthenticated() )
+ return;
+
+ account->deauthenticate();
+ account->setEnabled( false );
+ m_enabledAccounts.removeAll( account );
+
+ account->sync();
+}
+
+
+void
+AccountManager::connectAll()
+{
+ foreach( Account* acc, m_accounts )
+ {
+ acc->authenticate();
+ m_enabledAccounts << acc;
+
+ }
+ m_connected = true;
+}
+
+
+void
+AccountManager::disconnectAll()
+{
+ foreach( Account* acc, m_enabledAccounts )
+ acc->deauthenticate();
+
+ m_enabledAccounts.clear();
+ SourceList::instance()->removeAllRemote();
+ m_connected = false;
+}
+
+
+void
+AccountManager::toggleAccountsConnected()
+{
+ if ( m_connected )
+ disconnectAll();
+ else
+ connectAll();
+}
+
+
+void
+AccountManager::loadFromConfig()
+{
+ QStringList accountIds = TomahawkSettings::instance()->accounts();
+
+ foreach( const QString& accountId, accountIds )
+ {
+ QString pluginFactory = factoryFromId( accountId );
+ if( m_accountFactories.contains( pluginFactory ) )
+ {
+ Account* account = loadPlugin( accountId );
+ addAccount( account );
+ }
+ }
+}
+
+void
+AccountManager::initSIP()
+{
+ tDebug() << Q_FUNC_INFO;
+ foreach( Account* account, accounts() )
+ {
+ hookupAndEnable( account, true );
+ }
+}
+
+
+Account*
+AccountManager::loadPlugin( const QString& accountId )
+{
+ QString factoryName = factoryFromId( accountId );
+
+ Q_ASSERT( m_accountFactories.contains( factoryName ) );
+
+ Account* account = m_accountFactories[ factoryName ]->createAccount( accountId );
+ hookupAccount( account );
+
+ return account;
+}
+
+
+void
+AccountManager::addAccount( Account* account )
+{
+ tDebug() << Q_FUNC_INFO << "adding account plugin";
+ m_accounts.append( account );
+
+ if ( account->types() & Accounts::SipType )
+ m_accountsByAccountType[ Accounts::SipType ].append( account );
+ if ( account->types() & Accounts::InfoType )
+ m_accountsByAccountType[ Accounts::InfoType ].append( account );
+ if ( account->types() & Accounts::ResolverType )
+ m_accountsByAccountType[ Accounts::ResolverType ].append( account );
+ if ( account->types() & Accounts::StatusPushType )
+ m_accountsByAccountType[ Accounts::StatusPushType ].append( account );
+
+ if ( account->infoPlugin() )
+ InfoSystem::InfoSystem::instance()->addInfoPlugin( account->infoPlugin() );
+
+ emit added( account );
+}
+
+
+void
+AccountManager::removeAccount( Account* account )
+{
+ account->deauthenticate();
+
+ // emit before moving from list so accountmodel can get indexOf
+ emit removed( account );
+
+ m_accounts.removeAll( account );
+ m_enabledAccounts.removeAll( account );
+ m_connectedAccounts.removeAll( account );
+ foreach ( AccountType type, m_accountsByAccountType.keys() )
+ {
+ QList< Account* > accounts = m_accountsByAccountType.value( type );
+ accounts.removeAll( account );
+ m_accountsByAccountType[ type ] = accounts;
+ }
+
+ TomahawkSettings::instance()->removeAccount( account->accountId() );
+
+ account->removeFromConfig();
+ account->deleteLater();
+}
+
+
+void
+AccountManager::hookupAccount( Account* account ) const
+{
+ connect( account, SIGNAL( error( int, QString ) ), SLOT( onError( int, QString ) ) );
+ connect( account, SIGNAL( connectionStateChanged( Tomahawk::Accounts::Account::ConnectionState ) ), SLOT( onStateChanged( Tomahawk::Accounts::Account::ConnectionState ) ) );
+}
+
+
+void
+AccountManager::hookupAndEnable( Account* account, bool startup )
+{
+ SipPlugin* p = account->sipPlugin();
+ if ( p )
+ SipHandler::instance()->hookUpPlugin( p );
+
+ if ( account->enabled() && ( !startup || account->autoConnect() ) )
+ {
+ account->authenticate();
+ m_enabledAccounts << account;
+ }
+}
+
+
+void
+AccountManager::onError( int code, const QString& msg )
+{
+ Account* account = qobject_cast< Account* >( sender() );
+ Q_ASSERT( account );
+
+
+ qWarning() << "Failed to connect to SIP:" << account->accountFriendlyName() << code << msg;
+
+ if ( code == Account::AuthError )
+ {
+ emit authError( account );
+ }
+ else
+ {
+ QTimer::singleShot( 10000, account, SLOT( authenticate() ) );
+ }
+}
+
+void
+AccountManager::onSettingsChanged()
+{
+ foreach( Account* account, m_accounts )
+ {
+ if ( account->types() & Accounts::SipType && account->sipPlugin() )
+ account->sipPlugin()->checkSettings();
+ }
+}
+
+
+void
+AccountManager::onStateChanged( Account::ConnectionState state )
+{
+ Account* account = qobject_cast< Account* >( sender() );
+ Q_ASSERT( account );
+
+ if ( account->connectionState() == Account::Disconnected )
+ {
+ m_connectedAccounts.removeAll( account );
+ emit disconnected( account );
+ }
+ else if ( account->connectionState() == Account::Connected )
+ {
+ m_connectedAccounts << account;
+ emit connected( account );
+ }
+
+ emit stateChanged( account, state );
+}
+
+
+};
+
+};
diff --git a/src/libtomahawk/accounts/AccountManager.h b/src/libtomahawk/accounts/AccountManager.h
new file mode 100644
index 000000000..969edd27f
--- /dev/null
+++ b/src/libtomahawk/accounts/AccountManager.h
@@ -0,0 +1,108 @@
+/* === This file is part of Tomahawk Player - ===
+ *
+ * Copyright 2010-2011, Christian Muehlhaeuser
+ * 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 ACCOUNTMANAGER_H
+#define ACCOUNTMANAGER_H
+
+#include
+
+#include "typedefs.h"
+#include "dllmacro.h"
+#include "infosystem/infosystem.h"
+#include "sip/SipPlugin.h"
+#include "Account.h"
+
+namespace Tomahawk
+{
+
+namespace Accounts
+{
+
+class DLLEXPORT AccountManager : public QObject
+{
+ Q_OBJECT
+
+public:
+ static AccountManager* instance();
+
+ explicit AccountManager( QObject *parent );
+ virtual ~AccountManager();
+
+ void loadFromConfig();
+ void initSIP();
+
+ void enableAccount( Account* account );
+ void disableAccount( Account* account );
+
+ QList< AccountFactory* > factories() const { return m_accountFactories.values(); }
+ bool hasPluginWithFactory( const QString& factory ) const;
+ AccountFactory* factoryForAccount( Account* account ) const;
+
+ void addAccount( Account* account );
+ void hookupAndEnable( Account* account, bool startup = false ); /// Hook up signals and start the plugin
+ void removeAccount( Account* account );
+
+ QList< Account* > accounts() const { return m_accounts; };
+ QList< Account* > accounts( Tomahawk::Accounts::AccountType type ) const { return m_accountsByAccountType[ type ]; }
+
+public slots:
+ void connectAll();
+ void disconnectAll();
+ void toggleAccountsConnected();
+
+signals:
+ void added( Tomahawk::Accounts::Account* );
+ void removed( Tomahawk::Accounts::Account* );
+
+ void connected( Tomahawk::Accounts::Account* );
+ void disconnected( Tomahawk::Accounts::Account* );
+ void authError( Tomahawk::Accounts::Account* );
+
+ void stateChanged( Account* p, Accounts::Account::ConnectionState state );
+
+private slots:
+ void onStateChanged( Tomahawk::Accounts::Account::ConnectionState state );
+ void onError( int code, const QString& msg );
+
+ void onSettingsChanged();
+private:
+ QStringList findPluginFactories();
+ void loadPluginFactories( const QStringList &paths );
+ void loadPluginFactory( const QString &path );
+ QString factoryFromId( const QString& accountId ) const;
+
+ Account* loadPlugin( const QString &accountId );
+ void hookupAccount( Account* ) const;
+
+ QList< Account* > m_accounts;
+ QList< Account* > m_enabledAccounts;
+ QList< Account* > m_connectedAccounts;
+ bool m_connected;
+
+ QHash< AccountType, QList< Account* > > m_accountsByAccountType;
+ QHash< QString, AccountFactory* > m_accountFactories;
+
+ static AccountManager* s_instance;
+};
+
+};
+
+};
+
+#endif
diff --git a/src/libtomahawk/accounts/AccountModel.cpp b/src/libtomahawk/accounts/AccountModel.cpp
new file mode 100644
index 000000000..5775e1d24
--- /dev/null
+++ b/src/libtomahawk/accounts/AccountModel.cpp
@@ -0,0 +1,670 @@
+/* === 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 "AccountModel.h"
+
+#include "Account.h"
+#include "AccountModelNode.h"
+#include "AccountManager.h"
+#include "AtticaManager.h"
+#include "ResolverAccount.h"
+
+#include
+
+using namespace Tomahawk;
+using namespace Accounts;
+
+AccountModel::AccountModel( QObject* parent )
+ : QAbstractListModel( parent )
+{
+ connect( AtticaManager::instance(), SIGNAL( resolversLoaded( Attica::Content::List ) ), this, SLOT( loadData() ) );
+
+ connect( AccountManager::instance(), SIGNAL( added( Tomahawk::Accounts::Account* ) ), this, SLOT( accountAdded( Tomahawk::Accounts::Account* ) ) );
+ 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 ) ) );
+
+ loadData();
+}
+
+void
+AccountModel::loadData()
+{
+ beginResetModel();
+
+ qDeleteAll( m_accounts );
+ m_accounts.clear();
+
+ // Add all factories
+ QList< AccountFactory* > factories = AccountManager::instance()->factories();
+ QList< Account* > allAccounts = AccountManager::instance()->accounts();
+ foreach ( AccountFactory* fac, factories )
+ {
+ if ( !fac->allowUserCreation() )
+ continue;
+
+ qDebug() << "Creating factory node:" << fac->prettyName();
+ m_accounts << new AccountModelNode( fac );
+
+ // remove the accounts we are dealing with
+ foreach ( Account* acct, allAccounts )
+ {
+ if ( AccountManager::instance()->factoryForAccount( acct ) == fac )
+ allAccounts.removeAll( acct );
+ }
+ }
+
+ // add all attica resolvers (installed or uninstalled)
+ Attica::Content::List fromAttica = AtticaManager::instance()->resolvers();
+ foreach ( const Attica::Content& content, fromAttica )
+ {
+ qDebug() << "Loading ATTICA ACCOUNT with content:" << content.id() << content.name();
+ if ( AtticaManager::instance()->hasCustomAccountForAttica( content.id() ) )
+ {
+ Account* acct = AtticaManager::instance()->customAccountForAttica( content.id() );
+ Q_ASSERT( acct );
+ if ( acct )
+ {
+ m_accounts << new AccountModelNode( acct );
+ allAccounts.removeAll( acct );
+ }
+ } else
+ {
+ m_accounts << new AccountModelNode( content );
+
+ foreach ( Account* acct, AccountManager::instance()->accounts( Accounts::ResolverType ) )
+ {
+ if ( AtticaResolverAccount* resolver = qobject_cast< AtticaResolverAccount* >( acct ) )
+ {
+ if ( resolver->atticaId() == content.id() )
+ {
+ allAccounts.removeAll( acct );
+ }
+ }
+ }
+ }
+ }
+
+ // All other accounts we haven't dealt with yet
+ foreach ( Account* acct, allAccounts )
+ {
+ Q_ASSERT( !qobject_cast< AtticaResolverAccount* >( acct ) ); // This should be caught above in the attica list
+
+ if ( qobject_cast< ResolverAccount* >( acct ) && !qobject_cast< AtticaResolverAccount* >( acct ) )
+ m_accounts << new AccountModelNode( qobject_cast< ResolverAccount* >( acct ) );
+ else
+ m_accounts << new AccountModelNode( acct );
+ }
+
+ endResetModel();
+}
+
+
+QVariant
+AccountModel::data( const QModelIndex& index, int role ) const
+{
+ if ( !index.isValid() )
+ return QVariant();
+
+ if ( !hasIndex( index.row(), index.column(), index.parent() ) )
+ return QVariant();
+
+ const AccountModelNode* node = m_accounts.at( index.row() );
+ // This is a top-level item. 3 cases
+
+ switch ( node->type )
+ {
+ case AccountModelNode::FactoryType:
+ {
+ AccountFactory* fac = node->factory;
+ Q_ASSERT( fac );
+
+ switch ( role )
+ {
+ case Qt::DisplayRole:
+ return fac->prettyName();
+ case Qt::DecorationRole:
+ return fac->icon();
+ case StateRole:
+ return ShippedWithTomahawk;
+ case Qt::ToolTipRole:
+ case DescriptionRole:
+ return fac->description();
+ case CanRateRole:
+ return false;
+ case RowTypeRole:
+ return TopLevelFactory;
+ case AccountData:
+ return QVariant::fromValue< QObject* >( node->factory );
+ case ChildrenOfFactoryRole:
+ return QVariant::fromValue< QList< Tomahawk::Accounts::Account* > >( node->accounts );
+ case HasConfig:
+ return !node->accounts.isEmpty();
+ case AccountTypeRole:
+ return QVariant::fromValue< AccountTypes >( node->factory->types() );
+ case Qt::CheckStateRole:
+ {
+ if ( node->accounts.isEmpty() )
+ return Qt::Unchecked;
+
+ // If all are checked or unchecked, return that
+ bool someOn = false, someOff = false;
+ foreach ( const Account* acct, node->accounts )
+ {
+ if ( acct->enabled() )
+ someOn = true;
+ else
+ someOff = true;
+ }
+ if ( someOn && !someOff )
+ return Qt::Checked;
+ else if ( someOff & !someOn )
+ return Qt::Unchecked;
+ else
+ return Qt::PartiallyChecked;
+ }
+ default:
+ return QVariant();
+ }
+ }
+ case AccountModelNode::AtticaType:
+ {
+ Attica::Content c = node->atticaContent;
+ Q_ASSERT( !c.id().isNull() );
+
+ switch( role )
+ {
+ case Qt::DisplayRole:
+ return c.name();
+ case Qt::DecorationRole:
+ return QVariant::fromValue< QPixmap >( AtticaManager::instance()->iconForResolver( c ) );
+ case StateRole:
+ return (int)AtticaManager::instance()->resolverState( c );
+ case Qt::ToolTipRole:
+ case DescriptionRole:
+ return c.description();
+ case AuthorRole:
+ return c.author();
+ case RowTypeRole:
+ return TopLevelAccount;
+ case RatingRole:
+ return c.rating() / 20; // rating is out of 100
+ case DownloadCounterRole:
+ return c.downloads();
+ case CanRateRole:
+ return true;
+ case AccountTypeRole:
+ return QVariant::fromValue< AccountTypes >( AccountTypes( ResolverType ) );
+ case VersionRole:
+ return c.version();
+ case UserHasRatedRole:
+ return AtticaManager::instance()->userHasRated( c );
+ default:
+ ;
+ }
+
+ AtticaResolverAccount* atticaAcct = node->atticaAccount;
+ if ( atticaAcct )
+ {
+ // If the resolver is installed or on disk, we expose some additional data
+ switch ( role )
+ {
+ case HasConfig:
+ return atticaAcct->configurationWidget() != 0;
+ case Qt::CheckStateRole:
+ return atticaAcct->enabled() ? Qt::Checked : Qt::Unchecked;
+ case AccountData:
+ return QVariant::fromValue< QObject* >( atticaAcct );
+ case ConnectionStateRole:
+ return atticaAcct->connectionState();
+ default:
+ ;
+ }
+ }
+ return QVariant();
+ }
+ case AccountModelNode::ManualResolverType:
+ case AccountModelNode::UniqueFactoryType:
+ {
+ if ( role == RowTypeRole )
+ {
+ if ( node->type == AccountModelNode::ManualResolverType )
+ return TopLevelAccount;
+ else
+ return UniqueFactory;
+ }
+ else if ( role == CanDeleteRole )
+ {
+ return node->type == AccountModelNode::ManualResolverType;
+ }
+
+ Account* acct = 0;
+ if ( node->type == AccountModelNode::ManualResolverType )
+ acct = node->resolverAccount;
+ else if ( node->type == AccountModelNode::UniqueFactoryType )
+ acct = node->accounts.isEmpty() ? 0 : node->accounts.first();
+
+ // If there's no account*, then it means it's a unique factory that hasn't been created
+ if ( !acct )
+ {
+ Q_ASSERT( node->type == AccountModelNode::UniqueFactoryType );
+ Q_ASSERT( node->factory );
+
+ switch( role )
+ {
+ case Qt::DisplayRole:
+ return node->factory->prettyName();
+ case Qt::DecorationRole:
+ return node->factory->icon();
+ case Qt::ToolTipRole:
+ case DescriptionRole:
+ return node->factory->description();
+ case StateRole:
+ return Uninstalled;
+ case CanRateRole:
+ return false;
+ case AccountTypeRole:
+ return QVariant::fromValue< AccountTypes >( node->factory->types() );
+ default:
+ return QVariant();
+ }
+ }
+ else
+ {
+ switch ( role )
+ {
+ case Qt::DisplayRole:
+ return acct->accountFriendlyName();
+ case Qt::DecorationRole:
+ return acct->icon();
+ case DescriptionRole:
+ return node->type == AccountModelNode::ManualResolverType ? QString() : node->factory->description();
+ case Qt::CheckStateRole:
+ return acct->enabled() ? Qt::Checked : Qt::Unchecked;
+ case AccountData:
+ return QVariant::fromValue< QObject* >( acct );
+ case ConnectionStateRole:
+ return acct->connectionState();
+ case HasConfig:
+ return acct->configurationWidget() != 0;
+ case StateRole:
+ return Installed;
+ case ChildrenOfFactoryRole:
+ return QVariant::fromValue< QList< Tomahawk::Accounts::Account* > >( node->accounts );
+ case AccountTypeRole:
+ return QVariant::fromValue< AccountTypes >( acct->types() );
+ default:
+ return QVariant();
+ }
+ }
+ }
+ case AccountModelNode::CustomAccountType:
+ {
+ Q_ASSERT( node->customAccount );
+ Q_ASSERT( node->factory );
+
+ Account* account = node->customAccount;
+ // This is sort of ugly. CustomAccounts are pure Account*, but we know that
+ // some might also be linked to attica resolvers (not always). If that is the case
+ // they have a Attica::Content set on the node, so we use that to display some
+ // extra metadata and rating
+ const bool hasAttica = !node->atticaContent.id().isEmpty();
+
+ switch ( role )
+ {
+ case Qt::DisplayRole:
+ return account->accountFriendlyName();
+ case Qt::DecorationRole:
+ return account->icon();
+ case StateRole:
+ return ShippedWithTomahawk;
+ case Qt::ToolTipRole:
+ case DescriptionRole:
+ return hasAttica ? node->atticaContent.description() : node->factory->description();
+ case CanRateRole:
+ return hasAttica;
+ case AuthorRole:
+ return hasAttica ? node->atticaContent.author() : QString();
+ case RatingRole:
+ return hasAttica ? node->atticaContent.rating() / 20 : 0; // rating is out of 100
+ case DownloadCounterRole:
+ return hasAttica ? node->atticaContent.downloads() : QVariant();
+ case RowTypeRole:
+ return CustomAccount;
+ case AccountData:
+ return QVariant::fromValue< QObject* >( account );
+ case HasConfig:
+ return account->configurationWidget() != 0;
+ case AccountTypeRole:
+ return QVariant::fromValue< AccountTypes >( account->types() );
+ case Qt::CheckStateRole:
+ return account->enabled() ? Qt::Checked : Qt::Unchecked;
+ case ConnectionStateRole:
+ return account->connectionState();
+ default:
+ return QVariant();
+ }
+ }
+ }
+
+ return QVariant();
+}
+
+
+
+bool
+AccountModel::setData( const QModelIndex& index, const QVariant& value, int role )
+{
+ if ( !index.isValid() || !hasIndex( index.row(), index.column(), index.parent() ) )
+ return false;
+
+ AccountModelNode* node = m_accounts.at( index.row() );
+
+ if ( role == CheckboxClickedRole )
+ {
+ Account* acct = 0;
+ switch ( node->type )
+ {
+ case AccountModelNode::UniqueFactoryType:
+ {
+ const Qt::CheckState state = static_cast< Qt::CheckState >( value.toInt() );
+ if ( node->accounts.isEmpty() )
+ {
+ Q_ASSERT( state == Qt::Checked ); // How could we have a checked unique factory w/ no account??
+ // No account for this unique factory, create it
+ // Don't add it to node->accounts here, slot attached to accountmanager::accountcreated will do it for us
+ acct = node->factory->createAccount();
+ AccountManager::instance()->addAccount( acct );
+ TomahawkSettings::instance()->addAccount( acct->accountId() );
+ }
+ else
+ {
+ Q_ASSERT( node->accounts.size() == 1 );
+ acct = node->accounts.first();
+ }
+ break;
+ }
+ case AccountModelNode::AtticaType:
+ {
+ // This may or may not be installed. if it's not installed yet, install it, then go ahead and enable it
+ Q_ASSERT( node->atticaContent.isValid() );
+
+ Attica::Content resolver = node->atticaContent;
+ AtticaManager::ResolverState state = AtticaManager::instance()->resolverState( resolver );
+ qDebug() << "Attica resolver was checked! Current state is:" << state << "and so..";
+ if ( state == AtticaManager::Installed && !node->atticaAccount )
+ {
+ // Something is wrong, reinstall
+ qDebug() << "Found installed state but no resolver, uninstalling first";
+ AtticaManager::instance()->uninstallResolver( resolver );
+ state = AtticaManager::Uninstalled;
+ }
+
+ if ( state == AtticaManager::Installed )
+ {
+ qDebug() << "Already installed with resolver, just enabling";
+ acct = node->atticaAccount;
+ break;
+ }
+ else
+ {
+ if ( m_waitingForAtticaInstall.contains( resolver.id() ) )
+ {
+ // in progress, ignore
+ return true;
+ }
+
+ qDebug() << "Kicked off fetch+install, now waiting";
+ m_waitingForAtticaInstall.insert( resolver.id() );
+
+ AtticaManager::instance()->installResolver( resolver );
+ return true;
+ }
+
+ }
+ case AccountModelNode::ManualResolverType:
+ acct = node->resolverAccount;
+ break;
+ case AccountModelNode::CustomAccountType:
+ acct = node->customAccount;
+ break;
+ default:
+ ;
+ };
+
+ if ( node->type == AccountModelNode::FactoryType )
+ {
+ // Turn on or off all accounts for this factory
+
+ Qt::CheckState state = static_cast< Qt::CheckState >( value.toInt() );
+
+ foreach ( Account* acct, node->accounts )
+ {
+ state == Qt::Checked ? AccountManager::instance()->enableAccount( acct )
+ : AccountManager::instance()->disableAccount( acct );
+ }
+
+ emit dataChanged( index, index );
+ return true;
+ }
+
+ Q_ASSERT( acct );
+ Qt::CheckState state = static_cast< Qt::CheckState >( value.toInt() );
+
+ if ( state == Qt::Checked && !acct->enabled() )
+ AccountManager::instance()->enableAccount( acct );
+ else if( state == Qt::Unchecked )
+ AccountManager::instance()->disableAccount( acct );
+
+ emit dataChanged( index, index );
+
+ return true;
+ }
+
+ // The install/create/remove/etc button was clicked. Handle it properly depending on this item
+ if ( role == CustomButtonRole )
+ {
+ if ( node->type == AccountModelNode::FactoryType )
+ {
+ // Make a new account of this factory type
+ emit createAccount( node->factory );
+ return true;
+ }
+ else if ( node->type == AccountModelNode::ManualResolverType )
+ {
+ Q_ASSERT( node->resolverAccount );
+ AccountManager::instance()->removeAccount( node->resolverAccount );
+
+ return true;
+ }
+ Q_ASSERT( false ); // Should not be here, only the above two types should have this button
+ return false;
+ }
+
+
+ if ( role == RatingRole )
+ {
+ // We only support rating Attica resolvers for the moment.
+ Q_ASSERT( node->type == AccountModelNode::AtticaType );
+
+ AtticaManager::ResolverState state = AtticaManager::instance()->resolverState( node->atticaContent );
+ // For now only allow rating if a resolver is installed!
+ if ( state != AtticaManager::Installed && state != AtticaManager::NeedsUpgrade )
+ return false;
+ if ( AtticaManager::instance()->userHasRated( node->atticaContent ) )
+ return false;
+ node->atticaContent.setRating( value.toInt() * 20 );
+ AtticaManager::instance()->uploadRating( node->atticaContent );
+
+ emit dataChanged( index, index );
+
+ return true;
+ }
+
+ return false;
+}
+
+
+void
+AccountModel::accountAdded( Account* account )
+{
+ // Find the factory this belongs up, and update
+ qDebug() << "IN ACCOUNT ADDED, new account:" << account->accountFriendlyName();
+ AccountFactory* factory = AccountManager::instance()->factoryForAccount( account );
+ AtticaResolverAccount* attica = qobject_cast< AtticaResolverAccount* >( account );
+ for ( int i = 0; i < m_accounts.size(); i++ )
+ {
+ AccountModelNode* n = m_accounts.at( i );
+ bool thisIsTheOne = false;
+ qDebug() << "Checking for added account's related factory or attica:" << n->factory << attica;
+ if ( attica )
+ qDebug() << n->atticaContent.id() << n->atticaContent.name() << attica->atticaId();
+ if ( n->factory == factory )
+ {
+ n->accounts << account;
+ thisIsTheOne = true;
+ }
+ else if ( attica && n->atticaContent.id() == attica->atticaId() )
+ {
+
+ n->atticaAccount = attica;
+ n->atticaContent = AtticaManager::instance()->resolverForId( attica->atticaId() );
+ thisIsTheOne = true;
+
+ if ( m_waitingForAtticaInstall.contains( attica->atticaId() ) )
+ AccountManager::instance()->enableAccount( account );
+
+ m_waitingForAtticaInstall.remove( attica->atticaId() );
+ }
+
+ if ( thisIsTheOne )
+ {
+ const QModelIndex idx = index( i, 0, QModelIndex() );
+ dataChanged( idx, idx );
+
+ return;
+ }
+ }
+
+ // Ok, just a plain resolver. add it at the end
+ if ( ResolverAccount* resolver = qobject_cast< ResolverAccount* >( account ) )
+ {
+ Q_ASSERT( qobject_cast< AtticaResolverAccount* >( account ) == 0 ); // should NOT get attica accounts here, should be caught above
+ const int count = m_accounts.size();
+ beginInsertRows( QModelIndex(), count, count );
+ m_accounts << new AccountModelNode( resolver );
+ endInsertRows();
+
+ emit scrollTo( index( m_accounts.size() - 1, 0, QModelIndex() ) );
+ }
+}
+
+
+void
+AccountModel::accountStateChanged( Account* account , Account::ConnectionState )
+{
+ // Find the factory this belongs up, and update
+ AccountFactory* factory = AccountManager::instance()->factoryForAccount( account );
+ for ( int i = 0; i < m_accounts.size(); i++ )
+ {
+ AccountModelNode* n = m_accounts.at( i );
+ if ( n->type != AccountModelNode::FactoryType )
+ {
+ // If this is not a non-unique factory, it has as top-level account, so find that and update it
+ // For each type that this node could be, check the corresponding data
+ if ( ( n->type == AccountModelNode::UniqueFactoryType && n->accounts.size() && n->accounts.first() == account ) ||
+ ( n->type == AccountModelNode::AtticaType && n->atticaAccount && n->atticaAccount == account ) ||
+ ( n->type == AccountModelNode::ManualResolverType && n->resolverAccount && n->resolverAccount == account ) )
+ {
+ const QModelIndex idx = index( i, 0, QModelIndex() );
+ emit dataChanged( idx, idx );
+ }
+ }
+ else
+ {
+ for ( int k = 0; k < n->accounts.size(); k++ )
+ {
+ Account* childAccount = n->accounts.at( k );
+
+ if ( childAccount == account )
+ {
+ const QModelIndex idx = index( i, 0, QModelIndex() );
+ emit dataChanged( idx, idx );
+ }
+ }
+ }
+
+ }
+}
+
+
+void
+AccountModel::accountRemoved( Account* account )
+{
+ // Find the row this belongs to and update/remove
+ AccountFactory* factory = AccountManager::instance()->factoryForAccount( account );
+ qDebug() << "AccountModel got account removed:" << account->accountFriendlyName();
+ for ( int i = 0; i < m_accounts.size(); i++ )
+ {
+ AccountModelNode* n = m_accounts.at( i );
+
+ bool found = false;
+ // Account in a factory, remove child and update
+ if ( ( n->type == AccountModelNode::FactoryType && n->factory == factory ) ||
+ ( n->type == AccountModelNode::UniqueFactoryType && n->accounts.size() && n->accounts.first() == account ) )
+ {
+ n->accounts.removeAll( account );
+ found = true;
+ }
+
+ // Attica account, just clear the account but leave the attica shell
+ if ( n->type == AccountModelNode::AtticaType && n->atticaAccount && n->atticaAccount == account )
+ {
+ n->atticaAccount = 0;
+ found = true;
+ }
+
+ if ( found )
+ {
+ qDebug() << "Found account removed but we don't want to delete a row!" << i << n->type << n->factory;
+ const QModelIndex idx = index( i, 0, QModelIndex() );
+ emit dataChanged( idx, idx );
+
+ return;
+ }
+
+ // Manual resolver added, remove the row now
+ if ( n->type == AccountModelNode::ManualResolverType && n->resolverAccount && n->resolverAccount == account )
+ {
+ qDebug() << "Found account removed AND REMOVING IT FROM THE LIST!" << n->factory << n->type << n->accounts << i;
+
+ beginRemoveRows( QModelIndex(), i, i );
+ m_accounts.removeAt( i );
+ endRemoveRows();
+
+ return;
+ }
+ }
+}
+
+
+int
+AccountModel::rowCount( const QModelIndex& ) const
+{
+ return m_accounts.size();
+}
+
diff --git a/src/libtomahawk/accounts/AccountModel.h b/src/libtomahawk/accounts/AccountModel.h
new file mode 100644
index 000000000..4396dcd7a
--- /dev/null
+++ b/src/libtomahawk/accounts/AccountModel.h
@@ -0,0 +1,113 @@
+/* === 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 TOMAHAWK_ACCOUNTS_ACCOUNTMODEL_H
+#define TOMAHAWK_ACCOUNTS_ACCOUNTMODEL_H
+
+#include "dllmacro.h"
+
+#include "Account.h"
+
+#include
+
+
+namespace Tomahawk {
+
+namespace Accounts {
+
+class AccountModelNode;
+
+class DLLEXPORT AccountModel : public QAbstractListModel
+{
+ Q_OBJECT
+
+public:
+ enum Roles {
+ RowTypeRole = Qt::UserRole + 1, // RowType enum
+
+ // Used by top-level accounts
+ DescriptionRole = Qt::UserRole + 17,
+ StateRole = Qt::UserRole + 18, // ItemState,
+ RatingRole = Qt::UserRole + 19,
+ DownloadCounterRole = Qt::UserRole + 20,
+ VersionRole = Qt::UserRole + 21,
+ AuthorRole = Qt::UserRole + 22,
+ UserHasRatedRole = Qt::UserRole + 24,
+
+ // used by both
+ ConnectionStateRole = Qt::UserRole + 25,
+ HasConfig = Qt::UserRole + 26,
+ ErrorString = Qt::UserRole + 27,
+
+ // used by individual accounts
+ AccountData = Qt::UserRole + 28, // raw plugin
+ CanRateRole = Qt::UserRole + 32,
+ AccountTypeRole = Qt::UserRole + 33,
+ CanDeleteRole = Qt::UserRole + 34,
+
+ CheckboxClickedRole = Qt::UserRole + 29, // the checkbox for this row was toggled
+ CustomButtonRole = Qt::UserRole + 30, // the add account or remove account button
+
+ // Used by factories
+ ChildrenOfFactoryRole = Qt::UserRole + 31
+ };
+
+ enum RowType {
+ TopLevelFactory,
+ TopLevelAccount,
+ UniqueFactory,
+ CustomAccount
+ };
+
+ enum ItemState {
+ Uninstalled = 0, // Attica resolver states
+ Installing,
+ Installed,
+ NeedsUpgrade,
+ Upgrading,
+ Failed,
+ ShippedWithTomahawk, // Built-in account/factory state: Can't uninstall or uninstall, just create
+ };
+
+ explicit AccountModel( QObject* parent = 0 );
+
+ virtual QVariant data( const QModelIndex& index, int role = Qt::DisplayRole ) const;
+ virtual int rowCount( const QModelIndex& parent = QModelIndex() ) const;
+ virtual bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole);
+
+signals:
+ void createAccount( Tomahawk::Accounts::AccountFactory* factory );
+ void scrollTo( const QModelIndex& idx );
+
+private slots:
+ void loadData();
+
+ void accountAdded( Tomahawk::Accounts::Account* );
+ void accountRemoved( Tomahawk::Accounts::Account* );
+ void accountStateChanged( Account*, Accounts::Account::ConnectionState );
+
+private:
+ QList< AccountModelNode* > m_accounts;
+ QSet< QString > m_waitingForAtticaInstall;
+};
+
+}
+
+}
+
+#endif // TOMAHAWK_ACCOUNTS_ACCOUNTMODEL_H
diff --git a/src/libtomahawk/accounts/AccountModelFilterProxy.cpp b/src/libtomahawk/accounts/AccountModelFilterProxy.cpp
new file mode 100644
index 000000000..23dca5dfc
--- /dev/null
+++ b/src/libtomahawk/accounts/AccountModelFilterProxy.cpp
@@ -0,0 +1,72 @@
+/* === 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 "AccountModelFilterProxy.h"
+
+#include "AccountModel.h"
+
+
+using namespace Tomahawk;
+using namespace Accounts;
+
+AccountModelFilterProxy::AccountModelFilterProxy( QObject* parent )
+ : QSortFilterProxyModel(parent)
+ , m_filterType( NoType )
+{
+
+}
+
+
+void
+AccountModelFilterProxy::setSourceModel( QAbstractItemModel* sourceModel )
+{
+ connect( sourceModel, SIGNAL( scrollTo( QModelIndex ) ), this, SLOT( onScrollTo( QModelIndex ) ) );
+ QSortFilterProxyModel::setSourceModel( sourceModel );
+}
+
+
+bool
+AccountModelFilterProxy::filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent ) const
+{
+ if ( m_filterType == NoType )
+ return true;
+
+ const QModelIndex idx = sourceModel()->index( sourceRow, 0, sourceParent );
+ const AccountTypes types = static_cast< AccountTypes >( idx.data( AccountModel::AccountTypeRole ).value< AccountTypes >() );
+
+ return types.testFlag( m_filterType );
+
+}
+
+
+void
+AccountModelFilterProxy::setFilterType( AccountType type )
+{
+ if ( type == m_filterType )
+ return;
+
+ m_filterType = type;
+ invalidate();
+}
+
+
+void
+AccountModelFilterProxy::onScrollTo( const QModelIndex& idx )
+{
+ emit scrollTo( mapFromSource( idx ) );
+}
diff --git a/src/libtomahawk/accounts/AccountModelFilterProxy.h b/src/libtomahawk/accounts/AccountModelFilterProxy.h
new file mode 100644
index 000000000..92c61d469
--- /dev/null
+++ b/src/libtomahawk/accounts/AccountModelFilterProxy.h
@@ -0,0 +1,56 @@
+/* === 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 ACCOUNTMODELFILTERPROXY_H
+#define ACCOUNTMODELFILTERPROXY_H
+
+#include "Account.h"
+#include "dllmacro.h"
+
+#include
+
+namespace Tomahawk {
+namespace Accounts {
+
+class DLLEXPORT AccountModelFilterProxy : public QSortFilterProxyModel
+{
+ Q_OBJECT
+public:
+ AccountModelFilterProxy( QObject* parent = 0 );
+
+ void setFilterType( Tomahawk::Accounts::AccountType type );
+
+ virtual void setSourceModel( QAbstractItemModel* sourceModel );
+
+signals:
+ void scrollTo( const QModelIndex& idx );
+
+protected:
+ virtual bool filterAcceptsRow ( int sourceRow, const QModelIndex& sourceParent ) const;
+
+private slots:
+ void onScrollTo( const QModelIndex& idx );
+
+private:
+ Tomahawk::Accounts::AccountType m_filterType;
+};
+
+}
+
+}
+#endif // ACCOUNTMODELFILTERPROXY_H
diff --git a/src/libtomahawk/accounts/AccountModelNode.h b/src/libtomahawk/accounts/AccountModelNode.h
new file mode 100644
index 000000000..042d913cf
--- /dev/null
+++ b/src/libtomahawk/accounts/AccountModelNode.h
@@ -0,0 +1,145 @@
+/* === This file is part of Tomahawk Player - ===
+ *
+ * Copyright 2010-2011, Leo Franchi