1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-08-06 22:26:32 +02:00
Merge branch 'accounts'

Conflicts:
	resources.qrc
	src/accounts/zeroconf/zeroconf.cpp
This commit is contained in:
Leo Franchi
2012-03-07 18:23:32 -05:00
131 changed files with 7541 additions and 4348 deletions

View File

@@ -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")

View File

@@ -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.

BIN
data/images/lastfm-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@@ -134,6 +134,7 @@
<file>data/images/no-album-no-case.png</file>
<file>data/images/rdio.png</file>
<file>data/images/grooveshark.png</file>
<file>data/images/lastfm-icon.png</file>
<file>data/sql/dbmigrate-27_to_28.sql</file>
<file>data/images/process-stop.png</file>
</qresource>

650
src/AccountDelegate.cpp Normal file
View File

@@ -0,0 +1,650 @@
/*
Copyright (C) 2011 Leo Franchi <leo.franchi@kdab.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "AccountDelegate.h"
#include <QApplication>
#include <QPainter>
#include <QMouseEvent>
#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;
}

72
src/AccountDelegate.h Normal file
View File

@@ -0,0 +1,72 @@
/*
Copyright (C) 2011 Leo Franchi <leo.franchi@kdab.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ACCOUNTDELEGATE_H
#define ACCOUNTDELEGATE_H
#include <QStyledItemDelegate>
#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

View File

@@ -0,0 +1,149 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "AccountFactoryWrapper.h"
#include "accounts/Account.h"
#include <accounts/AccountManager.h>
#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();
}

View File

@@ -0,0 +1,66 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef ACCOUNTFACTORYWRAPPER_H
#define ACCOUNTFACTORYWRAPPER_H
#include <QDialog>
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

View File

@@ -0,0 +1,110 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AccountFactoryWrapper</class>
<widget class="QDialog" name="AccountFactoryWrapper">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>507</width>
<height>150</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="factoryIcon">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="factoryDescription">
<property name="text">
<string>Description goes here</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QTreeWidget" name="accountsList">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="autoScroll">
<bool>false</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::NoSelection</enum>
</property>
<property name="verticalScrollMode">
<enum>QAbstractItemView::ScrollPerItem</enum>
</property>
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<property name="headerHidden">
<bool>true</bool>
</property>
<property name="expandsOnDoubleClick">
<bool>false</bool>
</property>
<column>
<property name="text">
<string notr="true">1</string>
</property>
</column>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Close</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -0,0 +1,166 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "AccountFactoryWrapperDelegate.h"
#include "accounts/Account.h"
#include "AccountFactoryWrapper.h"
#include "utils/tomahawkutils.h"
#include <QApplication>
#include <QPainter>
#include <QMouseEvent>
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;
}

View File

@@ -1,6 +1,6 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
* Copyright 2010-2012, Leo Franchi <lfranchi@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef GETNEWSTUFFDELEGATE_H
#define GETNEWSTUFFDELEGATE_H
#ifndef ACCOUNTFACTORYWRAPPERDELEGATE_H
#define ACCOUNTFACTORYWRAPPERDELEGATE_H
#include <QStyledItemDelegate>
#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<int, int>, QRect > m_cachedButtonRects;
mutable QHash< QPair<int, int>, QRect > m_cachedStarRects;
mutable QHash< QPersistentModelIndex, QRect > m_cachedButtonRects;
mutable QHash< QPersistentModelIndex, QRect > m_cachedConfigRects;
};
#endif // GETNEWSTUFFDELEGATE_H
#endif // ACCOUNTFACTORYWRAPPERDELEGATE_H

View File

@@ -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} )

View File

@@ -1,323 +0,0 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "GetNewStuffDelegate.h"
#include "GetNewStuffModel.h"
#include "utils/tomahawkutils.h"
#include "utils/logger.h"
#include <QtGui/QPainter>
#include <QApplication>
#include <QMouseEvent>
#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<int, int>(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<int, int>(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<int, int>( index.row(), index.column() ) ) )
{
QRect rect = m_cachedButtonRects[ QPair<int, int>( 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<int, int>( index.row(), index.column() ) ) )
{
QRect fullStars = m_cachedStarRects[ QPair<int, int>( 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;
}

View File

@@ -1,54 +0,0 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2011, Leo Franchi <lfranchi@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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;
}

View File

@@ -1,67 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>GetNewStuffDialog</class>
<widget class="QDialog" name="GetNewStuffDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>449</width>
<height>282</height>
</rect>
</property>
<property name="windowTitle">
<string>Download New Resolvers</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QListView" name="listView"/>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>GetNewStuffDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>GetNewStuffDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@@ -1,156 +0,0 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "GetNewStuffModel.h"
#include "utils/tomahawkutils.h"
#include "utils/logger.h"
#include <QPixmap>
#include <QUrl>
#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;
}

View File

@@ -1,64 +0,0 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef GETNEWSTUFFMODEL_H
#define GETNEWSTUFFMODEL_H
#include <QModelIndex>
#include <attica/content.h>
#include <QPixmap>
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

View File

@@ -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 )

View File

@@ -1,6 +1,6 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2011, Leo Franchi <lfranchi@kde.org>
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef GETNEWSTUFFDIALOG_H
#define GETNEWSTUFFDIALOG_H
#ifndef ACCOUNTDLLMACRO_H
#define ACCOUNTDLLMACRO_H
#include <QDialog>
#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

View File

@@ -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} )

View File

@@ -0,0 +1,714 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
* Copyright 2011, Leo Franchi <lfranchi@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "twittersip.h"
#include <QtPlugin>
#include <QDateTime>
#include <QRegExp>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QStringList>
#include <QTweetLib/qtweetaccountverifycredentials.h>
#include <QTweetLib/qtweetuser.h>
#include <QTweetLib/qtweetstatus.h>
#include <QTweetLib/qtweetusershow.h>
#include <utils/tomahawkutils.h>
#include <tomahawksettings.h>
#include <database/database.h>
#include <network/servent.h>
#include "utils/logger.h"
#include "accounts/twitter/tomahawkoauthtwitter.h"
#include <accounts/twitter/twitteraccount.h>
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<QTweetFriendsTimeline>( new QTweetFriendsTimeline( m_cachedTwitterAuth.data(), this ) );
m_mentions = QWeakPointer<QTweetMentions>( new QTweetMentions( m_cachedTwitterAuth.data(), this ) );
m_directMessages = QWeakPointer<QTweetDirectMessages>( new QTweetDirectMessages( m_cachedTwitterAuth.data(), this ) );
m_directMessageNew = QWeakPointer<QTweetDirectMessageNew>( new QTweetDirectMessageNew( m_cachedTwitterAuth.data(), this ) );
m_directMessageDestroy = QWeakPointer<QTweetDirectMessageDestroy>( new QTweetDirectMessageDestroy( m_cachedTwitterAuth.data(), this ) );
connect( m_friendsTimeline.data(), SIGNAL( parsedStatuses(const QList< QTweetStatus > &) ), SLOT( friendsTimelineStatuses(const QList<QTweetStatus> &) ) );
connect( m_mentions.data(), SIGNAL( parsedStatuses(const QList< QTweetStatus > &) ), SLOT( mentionsStatuses(const QList<QTweetStatus> &) ) );
connect( m_directMessages.data(), SIGNAL( parsedDirectMessages(const QList<QTweetDMStatus> &)), SLOT( directMessages(const QList<QTweetDMStatus> &) ) );
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 &regex, 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();
}

View File

@@ -1,6 +1,7 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
* Copyright 2011, Leo Franchi <lfranchi@kde.org>
*
* 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 <QTimer>
#include <QWeakPointer>
#include <QSet>
@@ -34,50 +33,30 @@
#include <QTweetLib/qtweetmentions.h>
#include <QTweetLib/qtweetdmstatus.h>
#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 &regex, 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<QString> m_keyCache;
ConnectionState m_state;
QWeakPointer<TwitterConfigWidget > m_configWidget;
// for settings access
friend class TwitterConfigWidget;
Tomahawk::Accounts::Account::ConnectionState m_state;
};
#endif

View File

@@ -1,6 +1,6 @@
#include "tomahawkoauthtwitter.h"
#include <QInputDialog>
#include <QtGui/QInputDialog>
#include "utils/logger.h"

View File

@@ -0,0 +1,26 @@
#ifndef TOMAHAWKOAUTHTWITTERACCOUNT
#define TOMAHAWKOAUTHTWITTERACCOUNT
#include "accounts/accountdllmacro.h"
#include <utils/tomahawkutils.h>
#include <QTweetLib/qtweetlib_global.h>
#include <QTweetLib/oauthtwitter.h>
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

View File

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@@ -0,0 +1,186 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
* Copyright 2011, Leo Franchi <lfranchi@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "twitteraccount.h"
#include "twitterconfigwidget.h"
#include "accounts/twitter/tomahawkoauthtwitter.h"
#include "sip/SipPlugin.h"
#include <QTweetLib/qtweetaccountverifycredentials.h>
#include <QTweetLib/qtweetuser.h>
#include <QTweetLib/qtweetstatus.h>
#include <QTweetLib/qtweetusershow.h>
#include <QtCore/QtPlugin>
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 )

View File

@@ -0,0 +1,103 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
* Copyright 2011, Leo Franchi <lfranchi@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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

View File

@@ -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!") );
}
}
}

View File

@@ -16,10 +16,10 @@
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TWITTERCONFIGWIDGET_H
#define TWITTERCONFIGWIDGET_H
#ifndef TWITTERACCOUNTCONFIGWIDGET_H
#define TWITTERACCOUNTCONFIGWIDGET_H
#include "sip/SipPlugin.h"
#include "accounts/accountdllmacro.h"
#include <QTweetLib/qtweetstatus.h>
#include <QTweetLib/qtweetdmstatus.h>
@@ -28,24 +28,33 @@
#include <QWidget>
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

View File

@@ -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)

View File

@@ -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} )

View File

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

@@ -0,0 +1,122 @@
/*
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 2011 Leo Franchi <leo.franchi@kdab.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "googlewrapper.h"
#include "xmppconfigwidget.h"
#include "ui_xmppconfigwidget.h"
#include "utils/tomahawkutilsgui.h"
#include <QtPlugin>
#include <QInputDialog>
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

View File

@@ -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

View File

@@ -1,5 +1,5 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file>jabber-icon.png</file>
<file>xmpp-icon.png</file>
</qresource>
</RCC>

View File

@@ -21,12 +21,12 @@
#include <jreen/client.h>
#include <QObject>
#include <QDir>
#include <QtCore/QObject>
#include <QtCore/QDir>
#include "../sipdllmacro.h"
#include "accounts/accountdllmacro.h"
class SIPDLLEXPORT AvatarManager : public QObject
class ACCOUNTDLLEXPORT AvatarManager : public QObject
{
Q_OBJECT

View File

@@ -16,12 +16,12 @@
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#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;
}

View File

@@ -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<TomahawkSipMessagePrivate> d_ptr;
QScopedPointer<TomahawkXmppMessagePrivate> d_ptr;
};
#endif // ENTITYTIME_H

View File

@@ -16,7 +16,7 @@
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#include "tomahawksipmessagefactory.h"
#include "tomahawkxmppmessagefactory.h"
#include <QStringList>
#include <QXmlStreamWriter>
@@ -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<TomahawkSipMessage*>(extension);
TomahawkXmppMessage *sipMessage = se_cast<TomahawkXmppMessage*>(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());
}

View File

@@ -19,17 +19,17 @@
#ifndef ENTITYTIMEFACTORY_P_H
#define ENTITYTIMEFACTORY_P_H
#include "tomahawksipmessage.h"
#include "tomahawkxmppmessage.h"
#include <jreen/stanzaextension.h>
#include "../sipdllmacro.h"
#include "accounts/accountdllmacro.h"
class SIPDLLEXPORT TomahawkSipMessageFactory : public Jreen::PayloadFactory<TomahawkSipMessage>
class ACCOUNTDLLEXPORT TomahawkXmppMessageFactory : public Jreen::PayloadFactory<TomahawkXmppMessage>
{
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);

View File

@@ -23,18 +23,18 @@
#include <jreen/client.h>
#include <jreen/jid.h>
#include <QWidget>
#include <QXmlStreamReader>
#include <QDateTime>
#include <QTextBlock>
#include <QtGui/QWidget>
#include <QtXml/QXmlStreamReader>
#include <QtCore/QDateTime>
#include <QtGui/QTextBlock>
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

View File

@@ -2,6 +2,7 @@
*
* Copyright 2010-2011, Dominik Schmidt <dev@dominik-schmidt.de>
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
* Copyright 2011, Leo Franchi <lfranchi@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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 <jreen/jid.h>
#include <jreen/capabilities.h>
@@ -43,6 +42,10 @@
#include <QtCore/QDateTime>
#include <QtCore/QTimer>
#include <utils/tomahawkutils.h>
#include <utils/logger.h>
#include <accounts/AccountManager.h>
#ifndef ENABLE_HEADLESS
#include <QtGui/QInputDialog>
#include <QtGui/QLineEdit>
@@ -52,59 +55,33 @@
#include <utils/tomahawkutilsgui.h>
#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; i<TomahawkSettings::instance()->sipPlugins().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

View File

@@ -2,6 +2,7 @@
*
* Copyright 2010-2011, Dominik Schmidt <dev@dominik-schmidt.de>
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
* Copyright 2011, Leo Franchi <lfranchi@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef JABBER_H
#define JABBER_H
#ifndef XMPPSIP_H
#define XMPPSIP_H
#include "sip/SipPlugin.h"
@@ -45,70 +46,49 @@
#include <QtGui/QMessageBox>
#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;

View File

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@@ -0,0 +1,114 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
* Copyright 2011, Leo Franchi <lfranchi@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "xmppaccount.h"
#include "xmppconfigwidget.h"
#include "sip/SipPlugin.h"
#include "ui_xmppconfigwidget.h"
#include <QtCore/QtPlugin>
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

View File

@@ -0,0 +1,89 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Dominik Schmidt <dev@dominik-schmidt.de>
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
* Copyright 2011, Leo Franchi <lfranchi@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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

View File

@@ -0,0 +1,108 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "xmppaccount.h"
#include "xmppconfigwidget.h"
#include "ui_xmppconfigwidget.h"
#include <QMessageBox>
#include <accounts/AccountManager.h>
#include <utils/logger.h>
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 );
}
}
}

View File

@@ -0,0 +1,68 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef JABBERACCOUNTCONFIGWIDGET_H
#define JABBERACCOUNTCONFIGWIDGET_H
#include "accounts/accountdllmacro.h"
#include <QWidget>
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

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>JabberConfig</class>
<widget class="QWidget" name="JabberConfig">
<class>XmppConfigWidget</class>
<widget class="QWidget" name="XmppConfig">
<property name="geometry">
<rect>
<x>0</x>
@@ -11,7 +11,7 @@
</rect>
</property>
<property name="windowTitle">
<string>Jabber Configuration</string>
<string>Xmpp Configuration</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
@@ -35,7 +35,7 @@
<string/>
</property>
<property name="pixmap">
<pixmap resource="resources.qrc">:/jabber-icon.png</pixmap>
<pixmap resource="resources.qrc">:/xmpp-icon.png</pixmap>
</property>
</widget>
</item>
@@ -49,7 +49,7 @@
</font>
</property>
<property name="text">
<string>Configure this Jabber account</string>
<string>Configure this Xmpp account</string>
</property>
</widget>
</item>
@@ -84,9 +84,9 @@
</spacer>
</item>
<item>
<widget class="QLabel" name="jabberBlurb">
<widget class="QLabel" name="xmppBlurb">
<property name="text">
<string>Enter your Jabber login to connect with your friends using Tomahawk!</string>
<string>Enter your Xmpp login to connect with your friends using Tomahawk!</string>
</property>
</widget>
</item>
@@ -128,15 +128,15 @@
</size>
</property>
<property name="text">
<string>Jabber ID:</string>
<string>Xmpp ID:</string>
</property>
<property name="buddy">
<cstring>jabberUsername</cstring>
<cstring>xmppUsername</cstring>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="jabberUsername">
<widget class="QLineEdit" name="xmppUsername">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
@@ -160,12 +160,12 @@
<string>Password:</string>
</property>
<property name="buddy">
<cstring>jabberPassword</cstring>
<cstring>xmppPassword</cstring>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="jabberPassword">
<widget class="QLineEdit" name="xmppPassword">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
@@ -196,7 +196,7 @@
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBoxJabberAdvanced">
<widget class="QGroupBox" name="groupBoxXmppAdvanced">
<property name="enabled">
<bool>true</bool>
</property>
@@ -207,13 +207,13 @@
</sizepolicy>
</property>
<property name="title">
<string>Advanced Jabber Settings</string>
<string>Advanced Xmpp Settings</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="labelJabberServer">
<widget class="QLabel" name="labelXmppServer">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
@@ -233,12 +233,12 @@
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>jabberServer</cstring>
<cstring>xmppServer</cstring>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="jabberServer">
<widget class="QLineEdit" name="xmppServer">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
@@ -248,7 +248,7 @@
</widget>
</item>
<item>
<widget class="QLabel" name="labelJabberPort">
<widget class="QLabel" name="labelXmppPort">
<property name="text">
<string>Port:</string>
</property>
@@ -258,7 +258,7 @@
</widget>
</item>
<item>
<widget class="QSpinBox" name="jabberPort">
<widget class="QSpinBox" name="xmppPort">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>

View File

@@ -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} )

View File

@@ -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

View File

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

@@ -1,6 +1,7 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
* Copyright 2011, Leo Franchi <lfranchi@kde.org>
*
* 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 )

View File

@@ -1,6 +1,7 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
* Copyright 2011, Leo Franchi <lfranchi@kde.org>
*
* 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 <QtCore/QTimer>
#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<QStringList> m_cachedNodes;
QTimer m_advertisementTimer;
};
}
}
#endif

View File

@@ -0,0 +1,128 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2011, Leo Franchi <lfranchi@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "zeroconfaccount.h"
#include "sip/SipPlugin.h"
#include "zeroconf.h"
#include <QtCore/QtPlugin>
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 )

View File

@@ -0,0 +1,80 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2011, Leo Franchi <lfranchi@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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

View File

@@ -20,6 +20,5 @@
#cmakedefine LIBLASTFM_FOUND
#cmakedefine GLOOX_FOUND
#cmakedefine QCA2_FOUND
#cmakedefine LIBATTICA_FOUND
#endif // CONFIG_H_IN

View File

@@ -1,120 +0,0 @@
/*
Copyright (C) 2011 Leo Franchi <leo.franchi@kdab.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "configdelegatebase.h"
#include <QPainter>
#include <QApplication>
#include <QMouseEvent>
#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 );
}

View File

@@ -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<int> extraCheckRoles() const { return QList<int>(); }
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;

View File

@@ -22,28 +22,28 @@
#include <QDialogButtonBox>
#include <QVBoxLayout>
#include <QPushButton>
#include <QDebug>
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

View File

@@ -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);
}

View File

@@ -32,6 +32,8 @@
#include <QTimer>
#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() );
}

View File

@@ -26,12 +26,12 @@
#include <QPixmap>
#include "dllmacro.h"
#include "accounts/Account.h"
#ifdef LIBATTICA_FOUND
#include <attica/provider.h>
#include <attica/providermanager.h>
#include <attica/content.h>
#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

View File

@@ -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}/.. ..

View File

@@ -1,6 +1,7 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
*
* 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 <boost/function.hpp>
#include <QObject>
@@ -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; }

View File

@@ -21,53 +21,8 @@
#include <QDesktopServices>
#include "settingsdialog.h"
// #include <QDir>
//
// #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>("AtticaManager::StateHash");
}

View File

@@ -0,0 +1,211 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
* Copyright 2011, Leo Franchi <lfranchi@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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;
}
}
}

View File

@@ -0,0 +1,193 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
* Copyright 2011, Leo Franchi <lfranchi@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef ACCOUNT_H
#define ACCOUNT_H
#include <QtCore/QObject>
#include <QtCore/QVariantMap>
#include <QtGui/QWidget>
#include <QtGui/QIcon>
#include <QtCore/QString>
#include <QtCore/QUuid>
#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

View File

@@ -0,0 +1,410 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "AccountManager.h"
#include "config.h"
#include "sourcelist.h"
#include "ResolverAccount.h"
#include "LastFmAccount.h"
#include <QtCore/QLibrary>
#include <QtCore/QDir>
#include <QtCore/QPluginLoader>
#include <QtCore/QCoreApplication>
#include <QTimer>
#include <sip/SipHandler.h>
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<AccountFactory*>( 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 );
}
};
};

View File

@@ -0,0 +1,108 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef ACCOUNTMANAGER_H
#define ACCOUNTMANAGER_H
#include <QtCore/QObject>
#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

View File

@@ -0,0 +1,670 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "AccountModel.h"
#include "Account.h"
#include "AccountModelNode.h"
#include "AccountManager.h"
#include "AtticaManager.h"
#include "ResolverAccount.h"
#include <attica/content.h>
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();
}

View File

@@ -0,0 +1,113 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef TOMAHAWK_ACCOUNTS_ACCOUNTMODEL_H
#define TOMAHAWK_ACCOUNTS_ACCOUNTMODEL_H
#include "dllmacro.h"
#include "Account.h"
#include <QAbstractListModel>
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

View File

@@ -0,0 +1,72 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#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 ) );
}

View File

@@ -0,0 +1,56 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2012, Leo Franchi <lfranchi@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef ACCOUNTMODELFILTERPROXY_H
#define ACCOUNTMODELFILTERPROXY_H
#include "Account.h"
#include "dllmacro.h"
#include <QSortFilterProxyModel>
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

View File

@@ -0,0 +1,145 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef TOMAHAWK_ACCOUNTS_ACCOUNTMODELNODE_H
#define TOMAHAWK_ACCOUNTS_ACCOUNTMODELNODE_H
#include "Account.h"
#include "AccountManager.h"
#include "ResolverAccount.h"
#include "AtticaManager.h"
#include <attica/content.h>
namespace Tomahawk {
namespace Accounts {
/**
* Node for account tree.
*
* Basically a union with possible types:
* 1) AccountFactory* for all factories that have child accounts. Also a list of children
* 2) Attica::Content for AtticaResolverAccounts (with associated AtticaResolverAccount*) (all synchrotron resolvers)
* 3) ResolverAccount* for manually added resolvers (from file).
* 4) Account* for custom accounts. These may be hybrid infosystem/resolver/sip plugins or other special accounts
*
* These are the top-level items in tree.
*
* Top level nodes all look the same to the user. The only difference is that services that have login (and thus
* can have multiple logins at once) allow a user to create multiple children with specific login information.
* All other top level accounts (Account*, Attica::Content, ResolverAccount*) behave the same to the user, they can
* simply toggle on/off.
*
*/
struct AccountModelNode {
enum NodeType {
FactoryType,
UniqueFactoryType,
AtticaType,
ManualResolverType,
CustomAccountType
};
AccountModelNode* parent;
NodeType type;
/// 1, 4
AccountFactory* factory;
QList< Account* > accounts; // list of children accounts (actually existing and configured accounts)
/// 2.
Attica::Content atticaContent;
AtticaResolverAccount* atticaAccount;
/// 3.
ResolverAccount* resolverAccount;
/// 4.
Account* customAccount;
// Construct in one of four ways. Then access the corresponding members
explicit AccountModelNode( AccountFactory* fac ) : type( FactoryType )
{
init();
factory = fac;
if ( fac->isUnique() )
type = UniqueFactoryType;
// Initialize factory nodes with their children
foreach ( Account* acct, AccountManager::instance()->accounts() )
{
if ( AccountManager::instance()->factoryForAccount( acct ) == fac )
{
qDebug() << "Found account for factory:" << acct->accountFriendlyName();
accounts.append( acct );
}
}
}
explicit AccountModelNode( Attica::Content cnt ) : type( AtticaType )
{
init();
atticaContent = cnt;
qDebug() << "Creating attica model node for resolver:" << cnt.id();
foreach ( Account* acct, AccountManager::instance()->accounts( Accounts::ResolverType ) )
{
if ( AtticaResolverAccount* resolver = qobject_cast< AtticaResolverAccount* >( acct ) )
{
if ( resolver->atticaId() == atticaContent.id() )
{
qDebug() << "found atticaaccount :" << resolver->accountFriendlyName();
atticaAccount = resolver;
break;
}
}
}
}
explicit AccountModelNode( ResolverAccount* ra ) : type( ManualResolverType )
{
init();
resolverAccount = ra;
}
explicit AccountModelNode( Account* account ) : type( CustomAccountType )
{
init();
customAccount = account;
factory = AccountManager::instance()->factoryForAccount( account );
if ( CustomAtticaAccount* customAtticaAccount = qobject_cast< CustomAtticaAccount* >( account ) )
atticaContent = customAtticaAccount->atticaContent();
}
void init()
{
factory = 0;
atticaAccount = 0;
resolverAccount = 0;
customAccount = 0;
}
};
}
}
#endif // TOMAHAWK_ACCOUNTS_ACCOUNTMODELNODE_H

View File

@@ -0,0 +1,268 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2012, Leo Franchi <lfranchi@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "LastFmAccount.h"
#include "LastFmConfig.h"
#include "infosystem/infosystem.h"
#include "infosystem/infoplugins/generic/lastfmplugin.h"
#include "utils/tomahawkutils.h"
#include "resolvers/qtscriptresolver.h"
#include "AtticaManager.h"
#include "pipeline.h"
#include "accounts/AccountManager.h"
using namespace Tomahawk;
using namespace InfoSystem;
using namespace Accounts;
LastFmAccountFactory::LastFmAccountFactory()
{
m_icon.load( RESPATH "images/lastfm-icon.png" );
}
Account*
LastFmAccountFactory::createAccount( const QString& accountId )
{
return new LastFmAccount( accountId.isEmpty() ? generateId( factoryId() ) : accountId );
}
QPixmap
LastFmAccountFactory::icon() const
{
return m_icon;
}
LastFmAccount::LastFmAccount( const QString& accountId )
: CustomAtticaAccount( accountId )
{
m_infoPlugin = QWeakPointer< LastFmPlugin >( new LastFmPlugin( this ) );
setAccountFriendlyName( "Last.Fm" );
m_icon.load( RESPATH "images/lastfm-icon.png" );
AtticaManager::instance()->registerCustomAccount( "lastfm", this );
connect( AtticaManager::instance(), SIGNAL( resolverInstalled( QString ) ), this, SLOT( resolverInstalled( QString ) ) );
const Attica::Content res = AtticaManager::instance()->resolverForId( "lastfm" );
const AtticaManager::ResolverState state = AtticaManager::instance()->resolverState( res );
if ( state == AtticaManager::Installed )
{
hookupResolver();
}
}
LastFmAccount::~LastFmAccount()
{
delete m_infoPlugin.data();
delete m_resolver.data();
}
void
LastFmAccount::authenticate()
{
const Attica::Content res = AtticaManager::instance()->resolverForId( "lastfm" );
const AtticaManager::ResolverState state = AtticaManager::instance()->resolverState( res );
qDebug() << "Last.FM account authenticating...";
if ( m_resolver.isNull() && state == AtticaManager::Installed )
{
hookupResolver();
}
else if ( m_resolver.isNull() )
{
AtticaManager::instance()->installResolver( res, false );
}
else
{
m_resolver.data()->start();
}
emit connectionStateChanged( connectionState() );
}
void
LastFmAccount::deauthenticate()
{
if ( m_resolver.data()->running() )
m_resolver.data()->stop();
emit connectionStateChanged( connectionState() );
}
QWidget*
LastFmAccount::configurationWidget()
{
if ( m_configWidget.isNull() )
m_configWidget = QWeakPointer<LastFmConfig>( new LastFmConfig( this ) );
return m_configWidget.data();
}
Account::ConnectionState
LastFmAccount::connectionState() const
{
return (!m_resolver.isNull() && m_resolver.data()->running()) ? Account::Connected : Account::Disconnected;
}
QPixmap
LastFmAccount::icon() const
{
return m_icon;
}
InfoPlugin*
LastFmAccount::infoPlugin()
{
return m_infoPlugin.data();
}
bool
LastFmAccount::isAuthenticated() const
{
return !m_resolver.isNull() && m_resolver.data()->running();
}
void
LastFmAccount::saveConfig()
{
if ( !m_configWidget.isNull() )
{
setUsername( m_configWidget.data()->username() );
setPassword( m_configWidget.data()->password() );
setScrobble( m_configWidget.data()->scrobble() );
}
m_infoPlugin.data()->settingsChanged();
}
QString
LastFmAccount::password() const
{
return credentials().value( "password" ).toString();
}
void
LastFmAccount::setPassword( const QString& password )
{
QVariantHash creds = credentials();
creds[ "password" ] = password;
setCredentials( creds );
}
QString
LastFmAccount::sessionKey() const
{
return credentials().value( "sessionkey" ).toString();
}
void
LastFmAccount::setSessionKey( const QString& sessionkey )
{
QVariantHash creds = credentials();
creds[ "sessionkey" ] = sessionkey;
setCredentials( creds );
}
QString
LastFmAccount::username() const
{
return credentials().value( "username" ).toString();
}
void
LastFmAccount::setUsername( const QString& username )
{
QVariantHash creds = credentials();
creds[ "username" ] = username;
setCredentials( creds );
}
bool
LastFmAccount::scrobble() const
{
return configuration().value( "scrobble" ).toBool();
}
void
LastFmAccount::setScrobble( bool scrobble )
{
QVariantHash conf;
conf[ "scrobble" ] = scrobble;
setConfiguration( conf );
}
void
LastFmAccount::resolverInstalled( const QString &resolverId )
{
if ( resolverId == "lastfm" )
{
// We requested this install, so we want to launch it
hookupResolver();
AccountManager::instance()->enableAccount( this );
}
}
void
LastFmAccount::resolverChanged()
{
emit connectionStateChanged( connectionState() );
}
void
LastFmAccount::hookupResolver()
{
// If there is a last.fm resolver from attica installed, create the corresponding ExternalResolver* and hook up to it
const Attica::Content res = AtticaManager::instance()->resolverForId( "lastfm" );
const AtticaManager::ResolverState state = AtticaManager::instance()->resolverState( res );
Q_ASSERT( state == AtticaManager::Installed );
const AtticaManager::Resolver data = AtticaManager::instance()->resolverData( res.id() );
m_resolver = QWeakPointer< ExternalResolverGui >( qobject_cast< ExternalResolverGui* >( Pipeline::instance()->addScriptResolver( data.scriptPath, enabled() ) ) );
connect( m_resolver.data(), SIGNAL( changed() ), this, SLOT( resolverChanged() ) );
}
Attica::Content
LastFmAccount::atticaContent() const
{
return AtticaManager::instance()->resolverForId( "lastfm" );
}

View File

@@ -0,0 +1,113 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2012, Leo Franchi <lfranchi@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef LASTFMACCOUNT_H
#define LASTFMACCOUNT_H
#include "accounts/Account.h"
#include "AtticaManager.h"
#include <attica/content.h>
#include <QObject>
namespace Tomahawk {
class ExternalResolverGui;
namespace InfoSystem {
class LastFmPlugin;
}
namespace Accounts {
class LastFmConfig;
class LastFmAccountFactory : public AccountFactory
{
Q_OBJECT
public:
LastFmAccountFactory();
virtual Account* createAccount(const QString& accountId = QString());
virtual QString description() const { return tr( "Scrobble your tracks to last.fm, and find freely downloadable tracks to play" ); }
virtual QString factoryId() const { return "lastfmaccount"; }
virtual QString prettyName() const { return "Last.fm"; }
virtual AccountTypes types() const { return AccountTypes( InfoType | StatusPushType ); }
virtual bool allowUserCreation() const { return false; }
virtual QPixmap icon() const;
virtual bool isUnique() const { return true; }
private:
QPixmap m_icon;
};
/**
* 3.Last.Fm account is special. It is both an attica resolver *and* a InfoPlugin. We always want the infoplugin,
* but the user can install the attica resolver on-demand. So we take care of both there.
*
*/
class LastFmAccount : public CustomAtticaAccount
{
Q_OBJECT
public:
explicit LastFmAccount( const QString& accountId );
~LastFmAccount();
virtual void deauthenticate();
virtual void authenticate();
virtual SipPlugin* sipPlugin() { return 0; }
virtual Tomahawk::InfoSystem::InfoPlugin* infoPlugin();
virtual bool isAuthenticated() const;
virtual ConnectionState connectionState() const;
virtual QPixmap icon() const;
virtual QWidget* aclWidget() { return 0; }
virtual QWidget* configurationWidget();
virtual void saveConfig();
QString username() const;
void setUsername( const QString& );
QString password() const;
void setPassword( const QString& );
QString sessionKey() const;
void setSessionKey( const QString& );
bool scrobble() const;
void setScrobble( bool scrobble );
Attica::Content atticaContent() const;
private slots:
void resolverInstalled( const QString& resolverId );
void resolverChanged();
private:
void hookupResolver();
QWeakPointer<Tomahawk::ExternalResolverGui> m_resolver;
QWeakPointer<Tomahawk::InfoSystem::LastFmPlugin> m_infoPlugin;
QWeakPointer<LastFmConfig> m_configWidget;
QPixmap m_icon;
};
}
}
#endif // LASTFMACCOUNT_H

View File

@@ -0,0 +1,134 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "LastFmConfig.h"
#include "LastFmAccount.h"
#include <utils/tomahawkutils.h>
#include "ui_LastFmConfig.h"
#include "lastfm/ws.h"
#include "lastfm/XmlQuery"
using namespace Tomahawk::Accounts;
LastFmConfig::LastFmConfig( LastFmAccount* account )
: QWidget( 0 )
, m_account( account )
{
m_ui = new Ui_LastFmConfig;
m_ui->setupUi( this );
m_ui->username->setText( m_account->username() );
m_ui->password->setText( m_account->password() );
m_ui->enable->setChecked( m_account->scrobble() );
connect( m_ui->testLogin, SIGNAL( clicked( bool ) ), this, SLOT( testLogin( bool ) ) );
// #ifdef Q_WS_MAC // FIXME
// m_ui->testLogin->setVisible( false );
// #endif
}
QString
LastFmConfig::password() const
{
return m_ui->password->text();
}
bool
LastFmConfig::scrobble() const
{
return m_ui->enable->isChecked();
}
QString
LastFmConfig::username() const
{
return m_ui->username->text().trimmed();
}
void
LastFmConfig::testLogin(bool )
{
m_ui->testLogin->setEnabled( false );
m_ui->testLogin->setText( "Testing..." );
QString authToken = TomahawkUtils::md5( ( m_ui->username->text().toLower() + TomahawkUtils::md5( m_ui->password->text().toUtf8() ) ).toUtf8() );
// now authenticate w/ last.fm and get our session key
QMap<QString, QString> query;
query[ "method" ] = "auth.getMobileSession";
query[ "username" ] = m_ui->username->text().toLower();
query[ "authToken" ] = authToken;
// ensure they have up-to-date settings
lastfm::setNetworkAccessManager( TomahawkUtils::nam() );
QNetworkReply* authJob = lastfm::ws::post( query );
connect( authJob, SIGNAL( finished() ), SLOT( onLastFmFinished() ) );
}
void
LastFmConfig::onLastFmFinished()
{
QNetworkReply* authJob = dynamic_cast<QNetworkReply*>( sender() );
if( !authJob )
{
qDebug() << Q_FUNC_INFO << "No auth job returned!";
return;
}
if( authJob->error() == QNetworkReply::NoError )
{
lastfm::XmlQuery lfm = lastfm::XmlQuery( authJob->readAll() );
if( lfm.children( "error" ).size() > 0 )
{
qDebug() << "ERROR from last.fm:" << lfm.text();
m_ui->testLogin->setText( tr( "Failed" ) );
m_ui->testLogin->setEnabled( true );
}
else
{
m_ui->testLogin->setText( tr( "Success" ) );
m_ui->testLogin->setEnabled( false );
}
}
else
{
switch( authJob->error() )
{
case QNetworkReply::ContentOperationNotPermittedError:
case QNetworkReply::AuthenticationRequiredError:
m_ui->testLogin->setText( tr( "Failed" ) );
m_ui->testLogin->setEnabled( true );
break;
default:
qDebug() << "Couldn't get last.fm auth result";
m_ui->testLogin->setText( tr( "Could not contact server" ) );
m_ui->testLogin->setEnabled( true );
return;
}
}
}

View File

@@ -0,0 +1,53 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef LASTFMCONFIG_H
#define LASTFMCONFIG_H
#include <QWidget>
class Ui_LastFmConfig;
namespace Tomahawk {
namespace Accounts {
class LastFmAccount;
class LastFmConfig : public QWidget
{
Q_OBJECT
public:
explicit LastFmConfig( LastFmAccount* account );
QString username() const;
QString password() const;
bool scrobble() const;
public slots:
void testLogin( bool );
void onLastFmFinished();
private:
LastFmAccount* m_account;
Ui_LastFmConfig* m_ui;
};
}
}
#endif // LASTFMCONFIG_H

View File

@@ -0,0 +1,88 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>LastFmConfig</class>
<widget class="QWidget" name="LastFmConfig">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>220</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="margin">
<number>4</number>
</property>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="../../../resources.qrc">:/data/images/lastfm-icon.png</pixmap>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QCheckBox" name="enable">
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="text">
<string>Scrobble tracks to Last.fm</string>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Username:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="username"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Password:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="password">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QPushButton" name="testLogin">
<property name="text">
<string>Test Login</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources>
<include location="../../../resources.qrc"/>
</resources>
<connections/>
</ui>

View File

@@ -0,0 +1,245 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "ResolverAccount.h"
#include "ExternalResolver.h"
#include "ExternalResolverGui.h"
#include "AccountManager.h"
#include <pipeline.h>
#include <QFile>
#include <QFileInfo>
#include <QDir>
using namespace Tomahawk;
using namespace Accounts;
Account*
ResolverAccountFactory::createAccount( const QString& accountId )
{
// Can't use this to create new accounts. Needs to be able to find account in config
// to load proper resolver account type. Creation is done from AtticaManager when path is known
Q_ASSERT( !accountId.isEmpty() );
// If it's an attica resolver, return it instead so we get an icon
const bool isFromAttica = TomahawkSettings::instance()->value( QString( "accounts/%1/atticaresolver" ).arg( accountId ), false ).toBool();
if ( isFromAttica )
return new AtticaResolverAccount( accountId );
else
return new ResolverAccount( accountId );
}
Account*
ResolverAccountFactory::createFromPath( const QString& path, bool isAttica )
{
if ( isAttica )
{
QFileInfo info( path );
return new AtticaResolverAccount( generateId( "resolveraccount" ), path, info.baseName() );
}
else
return new ResolverAccount( generateId( "resolveraccount" ), path );
}
ResolverAccount::ResolverAccount( const QString& accountId )
: Account( accountId )
{
const QString path = configuration()[ "path" ].toString();
// We should have a valid saved path
Q_ASSERT( !path.isEmpty() );
m_resolver = QWeakPointer< ExternalResolverGui >( qobject_cast< ExternalResolverGui* >( Pipeline::instance()->addScriptResolver( path, enabled() ) ) );
connect( m_resolver.data(), SIGNAL( changed() ), this, SLOT( resolverChanged() ) );
// What resolver do we have here? Should only be types that are 'real' resolvers
Q_ASSERT ( !m_resolver.isNull() );
setAccountFriendlyName( m_resolver.data()->name() );
setTypes( AccountType( ResolverType ) );
}
ResolverAccount::ResolverAccount( const QString& accountId, const QString& path )
: Account( accountId )
{
QVariantHash configuration;
configuration[ "path" ] = path;
setConfiguration( configuration );
setEnabled( true );
m_resolver = QWeakPointer< ExternalResolverGui >( qobject_cast< ExternalResolverGui* >( Pipeline::instance()->addScriptResolver( path, true ) ) );
connect( m_resolver.data(), SIGNAL( changed() ), this, SLOT( resolverChanged() ) );
// What resolver do we have here? Should only be types that are 'real' resolvers
Q_ASSERT ( m_resolver.data() );
setAccountFriendlyName( m_resolver.data()->name() );
setTypes( AccountType( ResolverType ) );
}
ResolverAccount::~ResolverAccount()
{
if ( m_resolver.isNull() )
return;
Pipeline::instance()->removeScriptResolver( m_resolver.data()->filePath() );
delete m_resolver.data();
}
void
ResolverAccount::authenticate()
{
Q_ASSERT( !m_resolver.isNull() );
qDebug() << Q_FUNC_INFO << "Authenticating/starting resolver, exists?" << m_resolver;
if ( !m_resolver.data()->running() )
m_resolver.data()->start();
emit connectionStateChanged( connectionState() );
}
bool
ResolverAccount::isAuthenticated() const
{
return m_resolver.data()->running();
}
void
ResolverAccount::deauthenticate()
{
if ( m_resolver.data()->running() )
m_resolver.data()->stop();
emit connectionStateChanged( connectionState() );
}
Account::ConnectionState
ResolverAccount::connectionState() const
{
if ( m_resolver.data()->running() )
return Connected;
else
return Disconnected;
}
QWidget*
ResolverAccount::configurationWidget()
{
return m_resolver.data()->configUI();
}
QString
ResolverAccount::errorMessage() const
{
// TODO
// return m_resolver->error();
return QString();
}
void
ResolverAccount::removeFromConfig()
{
// TODO
Account::removeFromConfig();
}
void ResolverAccount::saveConfig()
{
Account::saveConfig();
m_resolver.data()->saveConfig();
}
QString
ResolverAccount::path() const
{
return m_resolver.data()->filePath();
}
void
ResolverAccount::resolverChanged()
{
setAccountFriendlyName( m_resolver.data()->name() );
emit connectionStateChanged( connectionState() );
}
/// AtticaResolverAccount
AtticaResolverAccount::AtticaResolverAccount( const QString& accountId )
: ResolverAccount( accountId )
{
TomahawkSettings::instance()->setValue( QString( "accounts/%1/atticaresolver" ).arg( accountId ), true );
m_atticaId = configuration().value( "atticaId" ).toString();
loadIcon();
}
AtticaResolverAccount::AtticaResolverAccount( const QString& accountId, const QString& path, const QString& atticaId )
: ResolverAccount( accountId, path )
, m_atticaId( atticaId )
{
QVariantHash conf = configuration();
conf[ "atticaId" ] = atticaId;
setConfiguration( conf );
TomahawkSettings::instance()->setValue( QString( "accounts/%1/atticaresolver" ).arg( accountId ), true );
loadIcon();
}
AtticaResolverAccount::~AtticaResolverAccount()
{
}
void
AtticaResolverAccount::loadIcon()
{
const QFileInfo fi( m_resolver.data()->filePath() );
QDir codeDir = fi.absoluteDir();
codeDir.cd( "../images" );
if ( codeDir.exists() && codeDir.exists( "icon.png" ) )
m_icon.load( codeDir.absoluteFilePath( "icon.png" ) );
}
QPixmap
AtticaResolverAccount::icon() const
{
return m_icon;
}

View File

@@ -0,0 +1,124 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef RESOLVERACCOUNT_H
#define RESOLVERACCOUNT_H
#include "accounts/Account.h"
#include "dllmacro.h"
namespace Tomahawk {
class ExternalResolverGui;
namespace Accounts {
class DLLEXPORT ResolverAccountFactory : public AccountFactory
{
Q_OBJECT
public:
ResolverAccountFactory() {}
virtual ~ResolverAccountFactory() {}
virtual Account* createAccount(const QString& accountId = QString());
virtual QString factoryId() const { return "resolveraccount"; }
virtual QString description() const { return QString(); }
virtual QString prettyName() const { return QString(); } // Internal, not displayed
AccountTypes types() const { return AccountTypes( ResolverType ); };
virtual bool allowUserCreation() const { return false; }
// Used to create a new resolver from a script on disk, either chosen by
// the user, or installed from synchrotron
static Account* createFromPath( const QString& path, bool isAttica );
};
/**
* Helper wrapper class that is a resolver-only account.
*
* Contains the resolver* that is it wrapping
*/
class DLLEXPORT ResolverAccount : public Account
{
Q_OBJECT
public:
// Loads from config. Must already exist.
explicit ResolverAccount( const QString& accountId );
virtual ~ResolverAccount();
virtual void authenticate();
virtual void deauthenticate();
virtual bool isAuthenticated() const;
virtual Tomahawk::Accounts::Account::ConnectionState connectionState() const;
virtual QWidget* configurationWidget();
virtual QString errorMessage() const;
virtual void saveConfig();
virtual void removeFromConfig();
QString path() const;
// Not relevant
virtual QPixmap icon() const { return QPixmap(); }
virtual SipPlugin* sipPlugin() { return 0; }
virtual Tomahawk::InfoSystem::InfoPlugin* infoPlugin() { return 0; }
virtual QWidget* aclWidget() { return 0; }
private slots:
void resolverChanged();
protected:
// Created by factory, when user installs a new resolver
ResolverAccount( const QString& accountId, const QString& path );
QWeakPointer<ExternalResolverGui> m_resolver;
friend class ResolverAccountFactory;
};
/**
* Extends ResolverAccount with what attica additionally provides---e.g. icon
* Assumes certain file layout on disk.
*/
class AtticaResolverAccount : public ResolverAccount
{
Q_OBJECT
public:
// Loads from config
explicit AtticaResolverAccount( const QString& accountId );
virtual ~AtticaResolverAccount();
virtual QPixmap icon() const;
QString atticaId() const { return m_atticaId; }
private:
// Created by factory, when user installs a new resolver
AtticaResolverAccount( const QString& accountId, const QString& path, const QString& atticaId );
void loadIcon();
QPixmap m_icon;
QString m_atticaId;
friend class ResolverAccountFactory;
};
}
}
#endif // RESOLVERACCOUNT_H

View File

@@ -1,74 +0,0 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef ACCOUNT_H
#define ACCOUNT_H
#include <QtCore/QObject>
#include <QtCore/QVariantMap>
#include <QtGui/QWidget>
#include "typedefs.h"
#include "dllmacro.h"
#include "infosystem/infosystem.h"
#include "sip/SipPlugin.h"
namespace Tomahawk
{
class DLLEXPORT Account
{
typedef QMap< QString, bool > ACLMap;
public:
enum AccountTypes { InfoType, SipType };
explicit Account();
virtual ~Account();
QString accountServiceName(); // e.g. "Twitter", "Last.fm"
void setAccountServiceName( const QString &serviceName );
QString accountFriendlyName(); // e.g. screen name on the service, JID, etc.
void setAccountFriendlyName( const QString &friendlyName );
bool autoConnect();
void setAutoConnect( bool autoConnect );
QStringMap credentials();
void setCredentials( const QStringMap &credentialMap );
QVariantMap configuration();
void setConfiguration( const QVariantMap &configuration );
QWidget* configurationWidget();
ACLMap acl();
void setAcl( const ACLMap &acl );
QWidget* aclWidget();
QSet< AccountTypes > types();
void setTypes( const QSet< AccountTypes > types );
Tomahawk::InfoSystem::InfoPlugin* infoPlugin();
SipPlugin* sipPlugin();
};
};
#endif // ACCOUNT_H

View File

@@ -250,6 +250,7 @@ void
DatabaseWorker::logOp( DatabaseCommandLoggable* command )
{
TomahawkSqlQuery oplogquery = m_dbimpl->newquery();
qDebug() << "INSERTING INTO OPTLOG:" << command->source()->id() << command->guid() << command->commandname();
oplogquery.prepare( "INSERT INTO oplog(source, guid, command, singleton, compressed, json) "
"VALUES(?, ?, ?, ?, ?, ?)" );

View File

@@ -323,12 +323,12 @@ hypemPlugin::chartReturned()
QList< InfoStringHash > top_tracks;
QStringList top_artists;
if( url.contains( "artists" ) )
if ( url.contains( "artists" ) )
setChartType( Artist );
else
setChartType( Track );
foreach(QVariant result, res )
foreach ( QVariant result, res )
{
QString title, artist;
QVariantMap chartMap = result.toMap();
@@ -339,28 +339,21 @@ hypemPlugin::chartReturned()
title = chartMap.value( "title" ).toString();
artist = chartMap.value( "artist" ).toString();
if( chartType() == Track )
if ( chartType() == Track )
{
InfoStringHash pair;
pair["artist"] = artist;
pair["track"] = title;
top_tracks << pair;
qDebug() << "HypemChart type is track";
}
if( chartType() == Artist )
{
if ( chartType() == Artist )
top_artists << artist;
qDebug() << "HypemChart type is artist";
}
}
}
if( chartType() == Track )
if ( chartType() == Track )
{
tDebug() << "HypemPlugin:" << "\tgot " << top_tracks.size() << " tracks";
returnedData["tracks"] = QVariant::fromValue( top_tracks );
@@ -369,7 +362,7 @@ hypemPlugin::chartReturned()
if( chartType() == Artist )
if ( chartType() == Artist )
{
tDebug() << "HypemPlugin:" << "\tgot " << top_artists.size() << " artists";
returnedData["artists"] = top_artists;

View File

@@ -26,34 +26,37 @@
#include "album.h"
#include "typedefs.h"
#include "audio/audioengine.h"
#include "tomahawksettings.h"
#include "utils/tomahawkutils.h"
#include "utils/logger.h"
#include "accounts/LastFmAccount.h"
#include <lastfm/ws.h>
#include <lastfm/XmlQuery>
#include <qjson/parser.h>
using namespace Tomahawk::Accounts;
using namespace Tomahawk::InfoSystem;
LastFmPlugin::LastFmPlugin()
LastFmPlugin::LastFmPlugin( LastFmAccount* account )
: InfoPlugin()
, m_account( account )
, m_scrobbler( 0 )
{
m_supportedGetTypes << InfoAlbumCoverArt << InfoArtistImages << InfoArtistSimilars << InfoArtistSongs << InfoChart << InfoChartCapabilities;
m_supportedPushTypes << InfoSubmitScrobble << InfoSubmitNowPlaying << InfoLove << InfoUnLove;
// Flush session key cache
TomahawkSettings::instance()->setLastFmSessionKey( QByteArray() );
// TODO WHY FLUSH
// m_account->setSessionKey( QByteArray() );
lastfm::ws::ApiKey = "7194b85b6d1f424fe1668173a78c0c4a";
lastfm::ws::SharedSecret = "ba80f1df6d27ae63e9cb1d33ccf2052f";
lastfm::ws::Username = TomahawkSettings::instance()->lastFmUsername();
lastfm::ws::Username = m_account->username();
lastfm::setNetworkAccessManager( TomahawkUtils::nam() );
m_pw = TomahawkSettings::instance()->lastFmPassword();
m_pw = m_account->password();
//HACK work around a bug in liblastfm---it doesn't create its config dir, so when it
// tries to write the track cache, it fails silently. until we have a fixed version, do this
@@ -69,9 +72,6 @@ LastFmPlugin::LastFmPlugin()
m_badUrls << QUrl( "http://cdn.last.fm/flatness/catalogue/noimage" );
connect( TomahawkSettings::instance(), SIGNAL( changed() ),
SLOT( settingsChanged() ), Qt::QueuedConnection );
QTimer::singleShot( 0, this, SLOT( settingsChanged() ) );
}
@@ -706,23 +706,23 @@ LastFmPlugin::artistImagesReturned()
void
LastFmPlugin::settingsChanged()
{
if ( !m_scrobbler && TomahawkSettings::instance()->scrobblingEnabled() )
if ( !m_scrobbler && m_account->scrobble() )
{ // can simply create the scrobbler
lastfm::ws::Username = TomahawkSettings::instance()->lastFmUsername();
m_pw = TomahawkSettings::instance()->lastFmPassword();
lastfm::ws::Username = m_account->username();
m_pw = m_account->password();
createScrobbler();
}
else if ( m_scrobbler && !TomahawkSettings::instance()->scrobblingEnabled() )
else if ( m_scrobbler && !m_account->scrobble() )
{
delete m_scrobbler;
m_scrobbler = 0;
}
else if ( TomahawkSettings::instance()->lastFmUsername() != lastfm::ws::Username ||
TomahawkSettings::instance()->lastFmPassword() != m_pw )
else if ( m_account->username() != lastfm::ws::Username ||
m_account->password() != m_pw )
{
lastfm::ws::Username = TomahawkSettings::instance()->lastFmUsername();
m_pw = TomahawkSettings::instance()->lastFmPassword();
lastfm::ws::Username = m_account->username();
m_pw = m_account->password();
// credentials have changed, have to re-create scrobbler for them to take effect
if ( m_scrobbler )
{
@@ -752,16 +752,16 @@ LastFmPlugin::onAuthenticated()
if ( lfm.children( "error" ).size() > 0 )
{
tLog() << "Error from authenticating with Last.fm service:" << lfm.text();
TomahawkSettings::instance()->setLastFmSessionKey( QByteArray() );
m_account->setSessionKey( QByteArray() );
}
else
{
lastfm::ws::SessionKey = lfm[ "session" ][ "key" ].text();
TomahawkSettings::instance()->setLastFmSessionKey( lastfm::ws::SessionKey.toLatin1() );
m_account->setSessionKey( lastfm::ws::SessionKey.toLatin1() );
// qDebug() << "Got session key from last.fm";
if ( TomahawkSettings::instance()->scrobblingEnabled() )
if ( m_account->scrobble() )
m_scrobbler = new lastfm::Audioscrobbler( "thk" );
}
}
@@ -777,7 +777,7 @@ LastFmPlugin::onAuthenticated()
void
LastFmPlugin::createScrobbler()
{
if ( TomahawkSettings::instance()->lastFmSessionKey().isEmpty() ) // no session key, so get one
if ( m_account->sessionKey().isEmpty() ) // no session key, so get one
{
qDebug() << "LastFmPlugin::createScrobbler Session key is empty";
QString authToken = TomahawkUtils::md5( ( lastfm::ws::Username.toLower() + TomahawkUtils::md5( m_pw.toUtf8() ) ).toUtf8() );
@@ -793,7 +793,7 @@ LastFmPlugin::createScrobbler()
else
{
qDebug() << "LastFmPlugin::createScrobbler Already have session key";
lastfm::ws::SessionKey = TomahawkSettings::instance()->lastFmSessionKey();
lastfm::ws::SessionKey = m_account->sessionKey();
m_scrobbler = new lastfm::Audioscrobbler( "thk" );
}

View File

@@ -32,6 +32,11 @@ class QNetworkReply;
namespace Tomahawk
{
namespace Accounts
{
class LastFmAccount;
}
namespace InfoSystem
{
@@ -40,7 +45,7 @@ class LastFmPlugin : public InfoPlugin
Q_OBJECT
public:
LastFmPlugin();
LastFmPlugin( Accounts::LastFmAccount* account );
virtual ~LastFmPlugin();
public slots:
@@ -74,6 +79,7 @@ private:
void dataError( Tomahawk::InfoSystem::InfoRequestData requestData );
Accounts::LastFmAccount* m_account;
QList<lastfm::Track> parseTrackList( QNetworkReply * reply );
lastfm::MutableTrack m_track;
@@ -88,3 +94,5 @@ private:
}
#endif // LASTFMPLUGIN_H
class A;

View File

@@ -1,6 +1,7 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
* Copyright 2012 Leo Franchi <lfranchi@kde.org>
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -45,6 +46,9 @@ InfoSystem* InfoSystem::s_instance = 0;
InfoSystem*
InfoSystem::instance()
{
if ( !s_instance )
s_instance = new InfoSystem( 0 );
return s_instance;
}
@@ -100,6 +104,9 @@ void
InfoSystem::init()
{
tDebug() << Q_FUNC_INFO;
if ( m_inited )
return;
if ( !m_infoSystemCacheThreadController->cache() || !m_infoSystemWorkerThreadController->worker() )
{
QTimer::singleShot( 0, this, SLOT( init() ) );
@@ -111,17 +118,17 @@ InfoSystem::init()
connect( cache, SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
worker, SLOT( infoSlot( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), Qt::UniqueConnection );
connect( worker, SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
this, SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), Qt::UniqueConnection );
connect( worker, SIGNAL( finished( QString ) ), this, SIGNAL( finished( QString ) ), Qt::UniqueConnection );
connect( worker, SIGNAL( finished( QString, Tomahawk::InfoSystem::InfoType ) ),
this, SIGNAL( finished( QString, Tomahawk::InfoSystem::InfoType ) ), Qt::UniqueConnection );
QMetaObject::invokeMethod( worker, "init", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoSystemCache*, cache ) );
m_inited = true;
}
@@ -195,6 +202,19 @@ InfoSystem::pushInfo( const QString &caller, const InfoTypeMap &input )
}
void
InfoSystem::addInfoPlugin( InfoPlugin* plugin )
{
// Init is not complete (waiting for worker th read to start and create worker object) so keep trying till then
if ( !m_inited || !m_infoSystemWorkerThreadController->worker() )
{
QMetaObject::invokeMethod( this, "addInfoPlugin", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoPlugin*, plugin ) );
return;
}
QMetaObject::invokeMethod( m_infoSystemWorkerThreadController->worker(), "addInfoPlugin", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoPlugin*, plugin ) );
}
InfoSystemCacheThread::InfoSystemCacheThread( QObject *parent )
: QThread( parent )
{

View File

@@ -134,7 +134,7 @@ struct InfoRequestData {
QVariantMap customData;
uint timeoutMillis;
bool allSources;
InfoRequestData()
: requestId( TomahawkUtils::infosystemRequestId() )
, internalId( TomahawkUtils::infosystemRequestId() )
@@ -145,7 +145,7 @@ struct InfoRequestData {
, timeoutMillis( 10000 )
, allSources( false )
{}
InfoRequestData( const quint64 rId, const QString &callr, const Tomahawk::InfoSystem::InfoType typ, const QVariant &inputvar, const QVariantMap &custom )
: requestId( rId )
, internalId( TomahawkUtils::infosystemRequestId() )
@@ -242,6 +242,10 @@ public:
bool pushInfo( const QString &caller, const InfoType type, const QVariant &input );
bool pushInfo( const QString &caller, const InfoTypeMap &input );
public slots:
// InfoSystem takes ownership of InfoPlugins
void addInfoPlugin( Tomahawk::InfoSystem::InfoPlugin* plugin );
signals:
void info( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output );
void finished( QString target );
@@ -249,7 +253,7 @@ signals:
private slots:
void init();
private:
bool m_inited;
InfoSystemCacheThread* m_infoSystemCacheThreadController;
@@ -289,5 +293,6 @@ Q_DECLARE_METATYPE( Tomahawk::InfoSystem::InfoRequestData );
Q_DECLARE_METATYPE( Tomahawk::InfoSystem::InfoStringHash );
Q_DECLARE_METATYPE( Tomahawk::InfoSystem::InfoSystemCache* );
Q_DECLARE_METATYPE( QList< Tomahawk::InfoSystem::InfoStringHash > );
Q_DECLARE_METATYPE( Tomahawk::InfoSystem::InfoPlugin* );
#endif // TOMAHAWK_INFOSYSTEM_H

View File

@@ -1,6 +1,7 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
* Copyright 2012 Leo Franchi <lfranchi@kde.org>
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -27,7 +28,6 @@
#include "infoplugins/generic/musixmatchplugin.h"
#include "infoplugins/generic/chartsplugin.h"
#include "infoplugins/generic/spotifyPlugin.h"
#include "infoplugins/generic/lastfmplugin.h"
#include "infoplugins/generic/musicbrainzPlugin.h"
#include "infoplugins/generic/hypemPlugin.h"
#include "utils/tomahawkutils.h"
@@ -41,7 +41,6 @@
#include "infoplugins/unix/mprisplugin.h"
#endif
#include "lastfm/NetworkAccessManager"
#include "infoplugins/generic/RoviPlugin.h"
namespace Tomahawk
@@ -78,71 +77,56 @@ void
InfoSystemWorker::init( Tomahawk::InfoSystem::InfoSystemCache* cache )
{
tDebug() << Q_FUNC_INFO;
m_cache = cache;
#ifndef ENABLE_HEADLESS
InfoPluginPtr enptr( new EchoNestPlugin() );
m_plugins.append( enptr );
registerInfoTypes( enptr, enptr.data()->supportedGetTypes(), enptr.data()->supportedPushTypes() );
InfoPluginPtr mmptr( new MusixMatchPlugin() );
m_plugins.append( mmptr );
registerInfoTypes( mmptr, mmptr.data()->supportedGetTypes(), mmptr.data()->supportedPushTypes() );
InfoPluginPtr mbptr( new MusicBrainzPlugin() );
m_plugins.append( mbptr );
registerInfoTypes( mbptr, mbptr.data()->supportedGetTypes(), mbptr.data()->supportedPushTypes() );
InfoPluginPtr lfmptr( new LastFmPlugin() );
m_plugins.append( lfmptr );
registerInfoTypes( lfmptr, lfmptr.data()->supportedGetTypes(), lfmptr.data()->supportedPushTypes() );
InfoPluginPtr sptr( new ChartsPlugin() );
m_plugins.append( sptr );
registerInfoTypes( sptr, sptr.data()->supportedGetTypes(), sptr.data()->supportedPushTypes() );
InfoPluginPtr roviptr( new RoviPlugin() );
m_plugins.append( roviptr );
registerInfoTypes( roviptr, roviptr.data()->supportedGetTypes(), roviptr.data()->supportedPushTypes() );
InfoPluginPtr spotptr( new SpotifyPlugin() );
m_plugins.append( spotptr );
registerInfoTypes( spotptr, spotptr.data()->supportedGetTypes(), spotptr.data()->supportedPushTypes() );
InfoPluginPtr hypeptr( new hypemPlugin() );
m_plugins.append( hypeptr );
registerInfoTypes( hypeptr, hypeptr.data()->supportedGetTypes(), hypeptr.data()->supportedPushTypes() );
addInfoPlugin( new EchoNestPlugin() );
addInfoPlugin( new MusixMatchPlugin() );
addInfoPlugin( new MusicBrainzPlugin() );
addInfoPlugin( new ChartsPlugin() );
addInfoPlugin( new RoviPlugin() );
addInfoPlugin( new SpotifyPlugin() );
addInfoPlugin( new hypemPlugin() );
#endif
#ifdef Q_WS_MAC
InfoPluginPtr admptr( new AdiumPlugin() );
m_plugins.append( admptr );
registerInfoTypes( admptr, admptr.data()->supportedGetTypes(), admptr.data()->supportedPushTypes() );
#endif
#ifndef ENABLE_HEADLESS
#ifdef Q_WS_X11
InfoPluginPtr fdonotifyptr( new FdoNotifyPlugin() );
m_plugins.append( fdonotifyptr );
registerInfoTypes( fdonotifyptr, fdonotifyptr.data()->supportedGetTypes(), fdonotifyptr.data()->supportedPushTypes() );
InfoPluginPtr mprisptr( new MprisPlugin() );
m_plugins.append( mprisptr );
registerInfoTypes( mprisptr, mprisptr.data()->supportedGetTypes(), mprisptr.data()->supportedPushTypes() );
#endif
#ifdef Q_WS_MAC
addInfoPlugin( new AdiumPlugin() );
#endif
Q_FOREACH( InfoPluginPtr plugin, m_plugins )
{
connect(
plugin.data(),
SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
this,
SLOT( infoSlot( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
Qt::UniqueConnection
);
#ifndef ENABLE_HEADLESS
#ifdef Q_WS_X11
addInfoPlugin( new FdoNotifyPlugin() );
addInfoPlugin( new MprisPlugin() );
#endif
#endif
}
connect(
plugin.data(),
SIGNAL( getCachedInfo( Tomahawk::InfoSystem::InfoStringHash, qint64, Tomahawk::InfoSystem::InfoRequestData ) ),
cache,
SLOT( getCachedInfoSlot( Tomahawk::InfoSystem::InfoStringHash, qint64, Tomahawk::InfoSystem::InfoRequestData ) )
);
connect(
plugin.data(),
SIGNAL( updateCache( Tomahawk::InfoSystem::InfoStringHash, qint64, Tomahawk::InfoSystem::InfoType, QVariant ) ),
cache,
SLOT( updateCacheSlot( Tomahawk::InfoSystem::InfoStringHash, qint64, Tomahawk::InfoSystem::InfoType, QVariant ) )
);
}
void
InfoSystemWorker::addInfoPlugin( InfoPlugin* plugin )
{
InfoPluginPtr weakptr( plugin );
m_plugins.append( weakptr );
registerInfoTypes( weakptr, weakptr.data()->supportedGetTypes(), weakptr.data()->supportedPushTypes() );
connect(
plugin,
SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
this,
SLOT( infoSlot( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
Qt::UniqueConnection
);
connect(
plugin,
SIGNAL( getCachedInfo( Tomahawk::InfoSystem::InfoStringHash, qint64, Tomahawk::InfoSystem::InfoRequestData ) ),
m_cache,
SLOT( getCachedInfoSlot( Tomahawk::InfoSystem::InfoStringHash, qint64, Tomahawk::InfoSystem::InfoRequestData ) )
);
connect(
plugin,
SIGNAL( updateCache( Tomahawk::InfoSystem::InfoStringHash, qint64, Tomahawk::InfoSystem::InfoType, QVariant ) ),
m_cache,
SLOT( updateCacheSlot( Tomahawk::InfoSystem::InfoStringHash, qint64, Tomahawk::InfoSystem::InfoType, QVariant ) )
);
}

View File

@@ -37,7 +37,9 @@ namespace Tomahawk {
namespace InfoSystem {
class InfoSystemCache;
class DLLEXPORT InfoSystemWorker : public QObject
{
Q_OBJECT
@@ -47,33 +49,37 @@ public:
~InfoSystemWorker();
void registerInfoTypes( const InfoPluginPtr &plugin, const QSet< InfoType > &getTypes, const QSet< InfoType > &pushTypes );
QNetworkAccessManager* nam() const;
signals:
void info( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output );
void finished( QString target );
void finished( QString target, Tomahawk::InfoSystem::InfoType type );
public slots:
void init( Tomahawk::InfoSystem::InfoSystemCache* cache );
void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData );
void pushInfo( QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input );
void infoSlot( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output );
void addInfoPlugin( Tomahawk::InfoSystem::InfoPlugin* plugin );
private slots:
void checkTimeoutsTimerFired();
private:
void checkFinished( const Tomahawk::InfoSystem::InfoRequestData &target );
QList< InfoPluginPtr > determineOrderedMatches( const InfoType type ) const;
QHash< QString, QHash< InfoType, int > > m_dataTracker;
QMultiMap< qint64, quint64 > m_timeRequestMapper;
QHash< uint, bool > m_requestSatisfiedMap;
QHash< uint, InfoRequestData* > m_savedRequestMap;
// NOTE Cache object lives in a different thread, do not call methods on it directly
InfoSystemCache* m_cache;
// For now, statically instantiate plugins; this is just somewhere to keep them
QList< InfoPluginPtr > m_plugins;

View File

@@ -65,7 +65,10 @@ Pipeline::~Pipeline()
m_running = false;
// stop script resolvers
qDeleteAll( m_scriptResolvers );
foreach ( QWeakPointer< ExternalResolver > r, m_scriptResolvers )
if ( !r.isNull() )
r.data()->deleteLater();
m_scriptResolvers.clear();
}
@@ -134,7 +137,7 @@ Pipeline::addScriptResolver( const QString& path, bool start )
if ( !res )
continue;
m_scriptResolvers << res;
m_scriptResolvers << QWeakPointer< ExternalResolver >( res );
if ( start )
res->start();
@@ -148,10 +151,10 @@ Pipeline::addScriptResolver( const QString& path, bool start )
void
Pipeline::stopScriptResolver( const QString& path )
{
foreach ( ExternalResolver* res, m_scriptResolvers )
foreach ( QWeakPointer< ExternalResolver > res, m_scriptResolvers )
{
if ( res->filePath() == path )
res->stop();
if ( res.data()->filePath() == path )
res.data()->stop();
}
}
@@ -159,18 +162,21 @@ Pipeline::stopScriptResolver( const QString& path )
void
Pipeline::removeScriptResolver( const QString& scriptPath )
{
ExternalResolver* r = 0;
foreach ( ExternalResolver* res, m_scriptResolvers )
QWeakPointer< ExternalResolver > r;
foreach ( QWeakPointer< ExternalResolver > res, m_scriptResolvers )
{
if ( res->filePath() == scriptPath )
if ( res.isNull() )
continue;
if ( res.data()->filePath() == scriptPath )
r = res;
}
m_scriptResolvers.removeAll( r );
if ( r )
if ( !r.isNull() )
{
r->stop();
r->deleteLater();
r.data()->stop();
r.data()->deleteLater();
}
}
@@ -178,10 +184,10 @@ Pipeline::removeScriptResolver( const QString& scriptPath )
ExternalResolver*
Pipeline::resolverForPath( const QString& scriptPath )
{
foreach ( ExternalResolver* res, m_scriptResolvers )
foreach ( QWeakPointer< ExternalResolver > res, m_scriptResolvers )
{
if ( res->filePath() == scriptPath )
return res;
if ( res.data()->filePath() == scriptPath )
return res.data();
}
return 0;
}

Some files were not shown because too many files have changed in this diff Show More