1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-08-06 06:07:37 +02:00

Merge branch 'aclwidget'. NOTE: If you have previous [acl] entries in

your Tomahawk.conf from previous testing, be sure to remove them, or
clear them from the button in Settings->Advanced.

Conflicts:
	ChangeLog
This commit is contained in:
Jeff Mitchell
2012-06-18 01:56:53 -04:00
21 changed files with 407 additions and 152 deletions

View File

@@ -1,4 +1,6 @@
Version 0.5.0: Version 0.5.0:
* Initial Access Control support. Entries can be cleared en masse in the Advanced area of Settings.
* Priortize resolution of a track on double-click.
* Spotify Resolver can now be easily installed on-demand from the settings. * Spotify Resolver can now be easily installed on-demand from the settings.
* You can now sync selected playlists (and updates) with Spotify. * You can now sync selected playlists (and updates) with Spotify.
* Support .aiff (AIFF mimetype) files. * Support .aiff (AIFF mimetype) files.

View File

@@ -30,6 +30,7 @@
#include <QtGui/QSizeGrip> #include <QtGui/QSizeGrip>
#include "AtticaManager.h" #include "AtticaManager.h"
#include "AclRegistry.h"
#include "TomahawkApp.h" #include "TomahawkApp.h"
#include "TomahawkSettings.h" #include "TomahawkSettings.h"
#include "accounts/DelegateConfigWrapper.h" #include "accounts/DelegateConfigWrapper.h"
@@ -98,6 +99,8 @@ SettingsDialog::SettingsDialog( QWidget *parent )
ui->enableProxyCheckBox->setChecked( useProxy ); ui->enableProxyCheckBox->setChecked( useProxy );
ui->proxyButton->setEnabled( useProxy ); ui->proxyButton->setEnabled( useProxy );
ui->aclEntryClearButton->setEnabled( TomahawkSettings::instance()->aclEntries().size() > 0 );
connect( ui->aclEntryClearButton, SIGNAL( clicked( bool ) ), this, SLOT( aclEntryClearButtonClicked() ) );
createIcons(); createIcons();
#ifdef Q_WS_X11 #ifdef Q_WS_X11
@@ -497,6 +500,24 @@ SettingsDialog::installFromFile()
} }
void
SettingsDialog::aclEntryClearButtonClicked()
{
QMessageBox::StandardButton button = QMessageBox::question(
ui->stackedWidget,
tr( "Delete all Access Control entries?" ),
tr( "Do you really want to delete all Access Control entries? You will be be asked for a decision again for each peer that you connect to." ),
QMessageBox::Ok | QMessageBox::Cancel,
QMessageBox::Ok
);
if ( button == QMessageBox::Ok )
{
ACLRegistry::instance()->wipeEntries();
ui->aclEntryClearButton->setEnabled( false );
}
}
void void
SettingsDialog::scrollTo( const QModelIndex& idx ) SettingsDialog::scrollTo( const QModelIndex& idx )
{ {

View File

@@ -97,6 +97,8 @@ private slots:
void changePage( QListWidgetItem*, QListWidgetItem* ); void changePage( QListWidgetItem*, QListWidgetItem* );
void serventReady(); void serventReady();
void aclEntryClearButtonClicked();
void requiresRestart(); void requiresRestart();
private: private:

View File

@@ -418,6 +418,30 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<layout class="QHBoxLayout" name="aclEntryClearLayout">
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="aclEntryClearButton">
<property name="text">
<string>Clear All Access Control Entries</string>
</property>
</widget>
</item>
</layout>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>

View File

@@ -799,7 +799,7 @@ XmppSipPlugin::onSubscriptionReceived( const Jreen::RosterItem::Ptr& item, const
QMessageBox *confirmBox = new QMessageBox( QMessageBox *confirmBox = new QMessageBox(
QMessageBox::Question, QMessageBox::Question,
tr( "Authorize User" ), tr( "Authorize User" ),
QString( tr( "Do you want to grant <b>%1</b> access to your Collection?" ) ).arg( presence.from().bare() ), QString( tr( "Do you want to add <b>%1</b> to your friend list?" ) ).arg( presence.from().bare() ),
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes | QMessageBox::No,
TomahawkUtils::tomahawkWindow() TomahawkUtils::tomahawkWindow()
); );

View File

@@ -35,6 +35,51 @@
#include "utils/Logger.h" #include "utils/Logger.h"
QDataStream& operator<<( QDataStream &out, const ACLRegistry::User &user )
{
out << ACLUSERVERSION;
out << user.uuid;
out << user.knownDbids.length();
foreach( QString knownDbid, user.knownDbids )
out << knownDbid;
out << user.knownAccountIds.length();
foreach( QString knownAccount, user.knownAccountIds )
out << knownAccount;
out << (int)( user.acl );
return out;
}
QDataStream& operator>>( QDataStream &in, ACLRegistry::User &user )
{
int ver;
in >> ver;
if ( ver == ACLUSERVERSION )
{
in >> user.uuid;
int dbidsLength;
in >> dbidsLength;
QString knownDbid;
for ( int i = 0; i < dbidsLength; i++ )
{
in >> knownDbid;
user.knownDbids << knownDbid;
}
int accountsLength;
in >> accountsLength;
QString knownAccountId;
for ( int i = 0; i < accountsLength; i++ )
{
in >> knownAccountId;
user.knownAccountIds << knownAccountId;
}
int aclIn;
in >> aclIn;
user.acl = (ACLRegistry::ACL)( aclIn );
}
return in;
}
ACLRegistry* ACLRegistry::s_instance = 0; ACLRegistry* ACLRegistry::s_instance = 0;
ACLRegistry* ACLRegistry*
@@ -53,7 +98,7 @@ ACLRegistry::ACLRegistry( QObject* parent )
s_instance = this; s_instance = this;
qRegisterMetaType< ACLRegistry::ACL >( "ACLRegistry::ACL" ); qRegisterMetaType< ACLRegistry::ACL >( "ACLRegistry::ACL" );
qRegisterMetaType< ACLRegistry::User >( "ACLRegistry::User" ); qRegisterMetaType< ACLRegistry::User >( "ACLRegistry::User" );
qRegisterMetaTypeStreamOperators< ACLRegistry::User >( "ACLRegistry::User" );
load(); load();
} }
@@ -66,17 +111,17 @@ ACLRegistry::~ACLRegistry()
ACLRegistry::ACL ACLRegistry::ACL
ACLRegistry::isAuthorizedUser( const QString& dbid, const QString &username, ACLRegistry::ACL globalType, bool skipEmission ) ACLRegistry::isAuthorizedUser( const QString& dbid, const QString &username, ACLRegistry::ACL globalType, bool skipEmission )
{ {
tLog() << Q_FUNC_INFO;
if ( QThread::currentThread() != TOMAHAWK_APPLICATION::instance()->thread() ) if ( QThread::currentThread() != TOMAHAWK_APPLICATION::instance()->thread() )
{ {
if ( !skipEmission ) if ( !skipEmission )
QMetaObject::invokeMethod( this, "isAuthorizedUser", Qt::QueuedConnection, Q_ARG( const QString&, dbid ), Q_ARG( const QString &, username ), Q_ARG( ACLRegistry::ACL, globalType ), Q_ARG( bool, skipEmission ) ); QMetaObject::invokeMethod( this, "isAuthorizedUser", Qt::QueuedConnection, Q_ARG( const QString&, dbid ), Q_ARG( const QString &, username ), Q_ARG( ACLRegistry::ACL, globalType ), Q_ARG( bool, skipEmission ) );
return ACLRegistry::NotFound; return ACLRegistry::NotFound;
} }
tLog() << Q_FUNC_INFO << "in right thread";
//FIXME: Remove when things are working //FIXME: Remove when things are working
emit aclResult( dbid, username, ACLRegistry::Stream ); // emit aclResult( dbid, username, ACLRegistry::Stream );
return ACLRegistry::NotFound; // return ACLRegistry::NotFound;
bool found = false; bool found = false;
QMutableListIterator< ACLRegistry::User > i( m_cache ); QMutableListIterator< ACLRegistry::User > i( m_cache );
while ( i.hasNext() ) while ( i.hasNext() )
@@ -139,28 +184,37 @@ ACLRegistry::isAuthorizedUser( const QString& dbid, const QString &username, ACL
void void
ACLRegistry::getUserDecision( ACLRegistry::User user, const QString &username ) ACLRegistry::getUserDecision( ACLRegistry::User user, const QString &username )
{ {
tLog() << Q_FUNC_INFO;
AclJobItem* job = new AclJobItem( user, username ); AclJobItem* job = new AclJobItem( user, username );
m_jobQueue.enqueue( job ); m_jobQueue.enqueue( job );
queueNextJob(); QTimer::singleShot( 0, this, SLOT( queueNextJob() ) );
} }
void void
ACLRegistry::userDecision( ACLRegistry::User user ) ACLRegistry::userDecision( ACLRegistry::User user )
{ {
tLog() << Q_FUNC_INFO;
m_cache.append( user ); m_cache.append( user );
save(); save();
emit aclResult( user.knownDbids.first(), user.knownAccountIds.first(), user.acl ); emit aclResult( user.knownDbids.first(), user.knownAccountIds.first(), user.acl );
m_jobCount--; m_jobCount--;
if ( !m_jobQueue.isEmpty() ) if ( !m_jobQueue.isEmpty() )
queueNextJob(); QTimer::singleShot( 0, this, SLOT( queueNextJob() ) );
} }
void void
ACLRegistry::queueNextJob() ACLRegistry::queueNextJob()
{ {
if ( QThread::currentThread() != TOMAHAWK_APPLICATION::instance()->thread() )
{
QMetaObject::invokeMethod( this, "queueNextJob", Qt::QueuedConnection );
return;
}
tLog() << Q_FUNC_INFO << "jobCount = " << m_jobCount;
tLog() << Q_FUNC_INFO << "jobQueue size = " << m_jobQueue.length();
if ( m_jobCount != 0 ) if ( m_jobCount != 0 )
return; return;
@@ -174,18 +228,21 @@ ACLRegistry::queueNextJob()
ACLRegistry::ACL acl = isAuthorizedUser( dbid, job->username(), ACLRegistry::NotFound, true ); ACLRegistry::ACL acl = isAuthorizedUser( dbid, job->username(), ACLRegistry::NotFound, true );
if ( acl != ACLRegistry::NotFound ) if ( acl != ACLRegistry::NotFound )
{ {
tLog() << Q_FUNC_INFO << "Found existing acl entry for = " << user.knownAccountIds.first();
found = true; found = true;
break; break;
} }
} }
if ( found ) if ( found )
{ {
tLog() << Q_FUNC_INFO << "deleting job, already have ACL for " << user.knownAccountIds.first();
delete job; delete job;
QTimer::singleShot( 0, this, SLOT( queueNextJob() ) ); QTimer::singleShot( 0, this, SLOT( queueNextJob() ) );
return; return;
} }
else else
{ {
tLog() << Q_FUNC_INFO << "activating job for user" << user.knownAccountIds.first();
m_jobCount++; m_jobCount++;
JobStatusView::instance()->model()->addJob( job ); JobStatusView::instance()->model()->addJob( job );
connect( job, SIGNAL( userDecision( ACLRegistry::User ) ), this, SLOT( userDecision( ACLRegistry::User ) ) ); connect( job, SIGNAL( userDecision( ACLRegistry::User ) ), this, SLOT( userDecision( ACLRegistry::User ) ) );
@@ -199,12 +256,22 @@ ACLRegistry::queueNextJob()
void void
ACLRegistry::load() ACLRegistry::load()
{ {
tLog() << Q_FUNC_INFO;
QVariantList entryList = TomahawkSettings::instance()->aclEntries(); QVariantList entryList = TomahawkSettings::instance()->aclEntries();
foreach ( QVariant entry, entryList ) foreach ( QVariant entry, entryList )
{ {
if ( !entry.isValid() || !entry.canConvert< ACLRegistry::User >() ) if ( !entry.isValid() || !entry.canConvert< ACLRegistry::User >() )
{
tLog() << Q_FUNC_INFO << "entry is invalid";
continue; continue;
}
tLog() << Q_FUNC_INFO << "loading entry";
ACLRegistry::User entryUser = entry.value< ACLRegistry::User >(); ACLRegistry::User entryUser = entry.value< ACLRegistry::User >();
if ( entryUser.knownAccountIds.empty() || entryUser.knownDbids.empty() )
{
tLog() << Q_FUNC_INFO << "user known account/dbids is empty";
continue;
}
m_cache.append( entryUser ); m_cache.append( entryUser );
} }
} }
@@ -213,8 +280,23 @@ ACLRegistry::load()
void void
ACLRegistry::save() ACLRegistry::save()
{ {
tLog() << Q_FUNC_INFO;
QVariantList entryList; QVariantList entryList;
foreach ( ACLRegistry::User user, m_cache ) foreach ( ACLRegistry::User user, m_cache )
entryList.append( QVariant::fromValue< ACLRegistry::User >( user ) ); {
tLog() << Q_FUNC_INFO << "user is " << user.uuid << " with known name " << user.knownAccountIds.first();
QVariant val = QVariant::fromValue< ACLRegistry::User >( user );
if ( val.isValid() )
entryList.append( val );
}
TomahawkSettings::instance()->setAclEntries( entryList ); TomahawkSettings::instance()->setAclEntries( entryList );
} }
void
ACLRegistry::wipeEntries()
{
tLog() << Q_FUNC_INFO;
m_cache.clear();
save();
}

View File

@@ -33,6 +33,8 @@
#include "HeadlessCheck.h" #include "HeadlessCheck.h"
#include "DllMacro.h" #include "DllMacro.h"
#define ACLUSERVERSION 1
class AclJobItem; class AclJobItem;
class DLLEXPORT ACLRegistry : public QObject class DLLEXPORT ACLRegistry : public QObject
@@ -54,19 +56,31 @@ public:
QString uuid; QString uuid;
QStringList knownDbids; QStringList knownDbids;
QStringList knownAccountIds; QStringList knownAccountIds;
ACL acl; ACLRegistry::ACL acl;
User() User()
: uuid( QUuid::createUuid().toString() ) : uuid( QUuid::createUuid().toString() )
, knownDbids()
, knownAccountIds()
, acl( ACLRegistry::NotFound ) , acl( ACLRegistry::NotFound )
{} {}
User( QString p_uuid, QStringList p_knownDbids, QStringList p_knownAccountIds, ACL p_acl ) ~User()
{}
User( QString p_uuid, QStringList p_knownDbids, QStringList p_knownAccountIds, ACLRegistry::ACL p_acl )
: uuid( p_uuid ) : uuid( p_uuid )
, knownDbids( p_knownDbids ) , knownDbids( p_knownDbids )
, knownAccountIds( p_knownAccountIds ) , knownAccountIds( p_knownAccountIds )
, acl( p_acl ) , acl( p_acl )
{} {}
User( const User &other )
: uuid( other.uuid )
, knownDbids( other.knownDbids )
, knownAccountIds( other.knownAccountIds )
, acl( other.acl )
{}
}; };
ACLRegistry( QObject *parent = 0 ); ACLRegistry( QObject *parent = 0 );
@@ -85,10 +99,11 @@ public slots:
* @return ACLRegistry::ACL * @return ACLRegistry::ACL
**/ **/
ACLRegistry::ACL isAuthorizedUser( const QString &dbid, const QString &username, ACLRegistry::ACL globalType = ACLRegistry::NotFound, bool skipEmission = false ); ACLRegistry::ACL isAuthorizedUser( const QString &dbid, const QString &username, ACLRegistry::ACL globalType = ACLRegistry::NotFound, bool skipEmission = false );
void wipeEntries();
#ifndef ENABLE_HEADLESS #ifndef ENABLE_HEADLESS
void getUserDecision( ACLRegistry::User user, const QString &username ); void getUserDecision( ACLRegistry::User user, const QString &username );
private slots: private slots:
void userDecision( ACLRegistry::User user ); void userDecision( ACLRegistry::User user );
void queueNextJob(); void queueNextJob();

View File

@@ -839,7 +839,10 @@ TomahawkSettings::aclEntries() const
void void
TomahawkSettings::setAclEntries( const QVariantList &entries ) TomahawkSettings::setAclEntries( const QVariantList &entries )
{ {
tDebug() << "Setting entries";
setValue( "acl/entries", entries ); setValue( "acl/entries", entries );
sync();
tDebug() << "Done setting entries";
} }

View File

@@ -27,6 +27,7 @@
#include "accounts/AccountManager.h" #include "accounts/AccountManager.h"
#include "utils/TomahawkUtils.h" #include "utils/TomahawkUtils.h"
#include "utils/TomahawkUtilsGui.h"
#include "utils/Logger.h" #include "utils/Logger.h"
#include "utils/AnimatedSpinner.h" #include "utils/AnimatedSpinner.h"
#include "utils/Closure.h" #include "utils/Closure.h"
@@ -549,53 +550,10 @@ AccountDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const QS
void void
AccountDelegate::drawRoundedButton( QPainter* painter, const QRect& btnRect, bool red ) const 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 ) if ( !red )
{ TomahawkUtils::drawRoundedButton( painter, btnRect, QColor(54, 127, 211), QColor(43, 104, 182), QColor(34, 85, 159), QColor(35, 79, 147) );
g.setColorAt( 0, QColor(54, 127, 211) );
g.setColorAt( 0.5, QColor(43, 104, 182) );
}
else else
{ TomahawkUtils::drawRoundedButton( painter, btnRect, QColor(206, 63, 63), QColor(170, 52, 52), QColor(150, 50, 50), QColor(130, 40, 40) );
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 );
} }

View File

@@ -21,31 +21,39 @@
#include "JobStatusModel.h" #include "JobStatusModel.h"
#include "utils/TomahawkUtils.h" #include "utils/TomahawkUtils.h"
#include "utils/TomahawkUtilsGui.h"
#include "libtomahawk/infosystem/InfoSystem.h"
#include "utils/Logger.h" #include "utils/Logger.h"
#include <QPixmap> #include <QPixmap>
#include <QPainter> #include <QPainter>
#include <QListView> #include <QListView>
#include <QApplication> #include <QApplication>
#include <QMouseEvent>
#define ROW_HEIGHT 40 #define ROW_HEIGHT 20
#define ICON_PADDING 1 #define ICON_PADDING 1
#define PADDING 2 #define PADDING 2
AclJobDelegate::AclJobDelegate( QObject* parent ) AclJobDelegate::AclJobDelegate( QObject* parent )
: QStyledItemDelegate ( parent ) : QStyledItemDelegate ( parent )
, m_parentView( qobject_cast< QListView* >( parent ) )
{ {
Q_ASSERT( m_parentView ); tLog() << Q_FUNC_INFO;
}
AclJobDelegate::~AclJobDelegate()
{
tLog() << Q_FUNC_INFO;
} }
void void
AclJobDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const AclJobDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const
{ {
tDebug( LOGVERBOSE ) << Q_FUNC_INFO; //tDebug( LOGVERBOSE ) << Q_FUNC_INFO;
QStyleOptionViewItemV4 opt = option; QStyleOptionViewItemV4 opt = option;
initStyleOption( &opt, index ); initStyleOption( &opt, index );
QFontMetrics fm( opt.font ); QFontMetrics fm( opt.font );
@@ -55,96 +63,91 @@ AclJobDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, co
painter->setRenderHint( QPainter::Antialiasing ); painter->setRenderHint( QPainter::Antialiasing );
painter->fillRect( opt.rect, Qt::lightGray );
QString mainText; QString mainText;
AclJobItem* item = dynamic_cast< AclJobItem* >( index.data( JobStatusModel::JobDataRole ).value< JobStatusItem* >() ); AclJobItem* item = dynamic_cast< AclJobItem* >( index.data( JobStatusModel::JobDataRole ).value< JobStatusItem* >() );
if ( !item ) if ( !item )
mainText = tr( "Error displaying ACL info" ); mainText = tr( "Error displaying ACL info" );
else else
mainText = QString( tr( "Allow %1 to\nconnect and stream from you?" ) ).arg( item->username() ); mainText = QString( tr( "Allow %1 to\nconnect and stream from you?" ) ).arg( item->username() );
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Displaying text:" << mainText; //tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Displaying text:" << mainText;
const QRect rRect( opt.rect.left() + PADDING, opt.rect.top() + 4*PADDING, opt.rect.width() - 2*PADDING, opt.rect.height() - 2*PADDING );
painter->drawText( rRect, Qt::AlignHCenter, mainText );
const QString text = QString( tr( "Allow %1 to\nconnect and stream from you?" ) ).arg( item->username() ); //tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Using rect " << rRect << ", opt rect is " << opt.rect;
const int w = fm.width( text );
Q_UNUSED( w ); // looks obsolete
const QRect rRect( opt.rect.left() + PADDING, ROW_HEIGHT + PADDING, opt.rect.width() - 2*PADDING, opt.rect.height() - 2*PADDING );
painter->drawText( rRect, Qt::AlignCenter, text );
int totalwidth = opt.rect.width();
int thirds = totalwidth/3;
QRect btnRect;
painter->setPen( Qt::white );
QString btnText = tr( "Allow Streaming" );
int btnWidth = fm.width( btnText ) + 2*PADDING;
btnRect = QRect( opt.rect.left() + thirds - btnWidth/2, opt.rect.bottom() - fm.height() - 4*PADDING, btnWidth + 2*PADDING, fm.height() + 2*PADDING );
drawRoundedButton( painter, btnRect, btnRect.contains( m_savedHoverPos ) );
painter->drawText( btnRect, Qt::AlignCenter, btnText );
m_savedAcceptRect = btnRect;
/* btnText = tr( "Deny Access" );
QStyleOptionViewItemV4 opt = option; btnWidth = fm.width( btnText ) + 2*PADDING;
initStyleOption( &opt, index ); btnRect = QRect( opt.rect.right() - thirds - btnWidth/2, opt.rect.bottom() - fm.height() - 4*PADDING, btnWidth + 2*PADDING, fm.height() + 2*PADDING );
QFontMetrics fm( opt.font ); drawRoundedButton( painter, btnRect, btnRect.contains( m_savedHoverPos ) );
const bool allowMultiLine = index.data( JobStatusModel::AllowMultiLineRole ).toBool(); painter->drawText( btnRect, Qt::AlignCenter, btnText );
m_savedDenyRect = btnRect;
opt.state &= ~QStyle::State_MouseOver;
QApplication::style()->drawPrimitive( QStyle::PE_PanelItemViewItem, &opt, painter, opt.widget );
// painter->drawLine( opt.rect.topLeft(), opt.rect.topRight() );
painter->setRenderHint( QPainter::Antialiasing );
QRect iconRect( ICON_PADDING, ICON_PADDING + opt.rect.y(), ROW_HEIGHT - 2*ICON_PADDING, ROW_HEIGHT - 2*ICON_PADDING );
if ( allowMultiLine )
iconRect.moveTop( opt.rect.top() + opt.rect.height() / 2 - iconRect.height() / 2);
QPixmap p = index.data( Qt::DecorationRole ).value< QPixmap >();
p = p.scaledToHeight( iconRect.height(), Qt::SmoothTransformation );
painter->drawPixmap( iconRect, p );
// draw right column if there is one
const QString rCol = index.data( JobStatusModel::RightColumnRole ).toString();
int rightEdge = opt.rect.right();
if ( !rCol.isEmpty() )
{
const int w = fm.width( rCol );
const QRect rRect( opt.rect.right() - PADDING - w, PADDING + opt.rect.y(), w, opt.rect.height() - 2*PADDING );
painter->drawText( rRect, Qt::AlignCenter, rCol );
rightEdge = rRect.left();
}
QString mainText;
AclJobItem* item = dynamic_cast< AclJobItem* >( index.data( JobStatusModel::JobDataRole ).value< JobStatusItem* >() );
//QString mainText = index.data( Qt::DisplayRole ).toString();
if ( !item )
mainText = tr( "Error displaying ACL info" );
else
mainText = QString( tr( "Allow %1 to\nconnect and stream from you?" ) ).arg( item->username() );
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Displaying text:" << mainText;
const int mainW = rightEdge - 3*PADDING - iconRect.right();
QTextOption to( Qt::AlignLeft | Qt::AlignVCenter );
if ( !allowMultiLine )
mainText = fm.elidedText( mainText, Qt::ElideRight, mainW );
else
to.setWrapMode( QTextOption::WrapAtWordBoundaryOrAnywhere );
painter->drawText( QRect( iconRect.right() + 2*PADDING, PADDING + opt.rect.y(), mainW, opt.rect.height() - 2*PADDING ), mainText, to );
*/
} }
QSize QSize
AclJobDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const AclJobDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const
{ {
tDebug( LOGVERBOSE ) << Q_FUNC_INFO; QSize size( QStyledItemDelegate::sizeHint ( option, index ).width(), ROW_HEIGHT * 3 );
return QSize( QStyledItemDelegate::sizeHint ( option, index ).width(), ROW_HEIGHT ); return size;
}
/*
const bool allowMultiLine = index.data( JobStatusModel::AllowMultiLineRole ).toBool();
if ( !allowMultiLine ) void
return QSize( QStyledItemDelegate::sizeHint ( option, index ).width(), ROW_HEIGHT ); AclJobDelegate::drawRoundedButton( QPainter* painter, const QRect& btnRect, bool red ) const
else if ( m_cachedMultiLineHeights.contains( index ) ) {
return QSize( QStyledItemDelegate::sizeHint ( option, index ).width(), m_cachedMultiLineHeights[ index ] ); if ( !red )
TomahawkUtils::drawRoundedButton( painter, btnRect, QColor(54, 127, 211), QColor(43, 104, 182), QColor(34, 85, 159), QColor(35, 79, 147) );
else
TomahawkUtils::drawRoundedButton( painter, btnRect, QColor(206, 63, 63), QColor(170, 52, 52), QColor(150, 50, 50), QColor(130, 40, 40) );
}
// Don't elide, but stretch across as many rows as required
QStyleOptionViewItemV4 opt = option;
initStyleOption( &opt, index );
const QString text = index.data( Qt::DisplayRole ).toString(); bool
const int leftEdge = ICON_PADDING + ROW_HEIGHT + 2*PADDING; AclJobDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index )
const QRect rect = opt.fontMetrics.boundingRect( leftEdge, opt.rect.top(), m_parentView->width() - leftEdge, 200, Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, text ); {
Q_UNUSED( option )
Q_UNUSED( model )
//tDebug( LOGVERBOSE ) << Q_FUNC_INFO;
if ( event->type() != QEvent::MouseButtonPress &&
event->type() != QEvent::MouseButtonRelease &&
event->type() != QEvent::MouseButtonDblClick &&
event->type() != QEvent::MouseMove )
return false;
m_cachedMultiLineHeights.insert( index, rect.height() + 4*PADDING ); if ( event->type() == QEvent::MouseMove )
{
QMouseEvent* me = static_cast< QMouseEvent* >( event );
m_savedHoverPos = me->pos();
//tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Setting position to " << m_savedHoverPos;
emit update( index );
return true;
}
return QSize( QStyledItemDelegate::sizeHint ( option, index ).width(), rect.height() + 4*PADDING ); if ( event->type() == QEvent::MouseButtonRelease || event->type() == QEvent::MouseButtonDblClick )
*/ {
QMouseEvent* me = static_cast< QMouseEvent* >( event );
if ( m_savedAcceptRect.contains( me->pos() ) )
emit aclResult( ACLRegistry::Stream );
else if ( m_savedDenyRect.contains( me->pos() ) )
emit aclResult( ACLRegistry::Deny );
return true;
}
return false;
} }
@@ -154,27 +157,44 @@ AclJobItem::AclJobItem( ACLRegistry::User user, const QString &username )
, m_user( user ) , m_user( user )
, m_username( username ) , m_username( username )
{ {
tLog() << Q_FUNC_INFO;
} }
AclJobItem::~AclJobItem() AclJobItem::~AclJobItem()
{ {
tLog() << Q_FUNC_INFO;
} }
void void
AclJobItem::createDelegate( QObject* parent ) AclJobItem::createDelegate( QObject* parent )
{ {
tLog() << Q_FUNC_INFO;
if ( m_delegate ) if ( m_delegate )
return; return;
m_delegate = new AclJobDelegate( parent ); m_delegate = new AclJobDelegate( parent );
Tomahawk::InfoSystem::InfoPushData pushData( "AclJobItem", Tomahawk::InfoSystem::InfoNotifyUser, tr( "Tomahawk needs you to decide whether %1 is allowed to connect." ).arg( m_username ), Tomahawk::InfoSystem::PushNoFlag );
Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo( pushData );
} }
void void
AclJobItem::done() AclJobDelegate::emitSizeHintChanged( const QModelIndex& index )
{ {
emit sizeHintChanged( index );
}
void
AclJobItem::aclResult( ACLRegistry::ACL result )
{
tLog() << Q_FUNC_INFO;
m_user.acl = result;
emit userDecision( m_user );
emit finished(); emit finished();
} }

View File

@@ -33,14 +33,26 @@ class AclJobDelegate : public QStyledItemDelegate
public: public:
explicit AclJobDelegate ( QObject* parent = 0 ); explicit AclJobDelegate ( QObject* parent = 0 );
virtual ~AclJobDelegate() {} virtual ~AclJobDelegate();
virtual void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const; virtual void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
virtual QSize sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const; virtual QSize sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const;
virtual void emitSizeHintChanged( const QModelIndex &index );
signals:
void update( const QModelIndex& idx );
void aclResult( ACLRegistry::ACL result );
protected:
virtual bool editorEvent( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index );
private: private:
mutable QHash< QPersistentModelIndex, int > m_cachedMultiLineHeights; void drawRoundedButton( QPainter* painter, const QRect& btnRect, bool red = false ) const;
QListView* m_parentView;
QPoint m_savedHoverPos;
mutable QRect m_savedAcceptRect;
mutable QRect m_savedDenyRect;
}; };
@@ -51,8 +63,6 @@ public:
explicit AclJobItem( ACLRegistry::User user, const QString &username ); explicit AclJobItem( ACLRegistry::User user, const QString &username );
virtual ~AclJobItem(); virtual ~AclJobItem();
void done();
virtual QString rightColumnText() const { return QString(); } virtual QString rightColumnText() const { return QString(); }
virtual QString mainText() const { return QString(); } virtual QString mainText() const { return QString(); }
virtual QPixmap icon() const { return QPixmap(); } virtual QPixmap icon() const { return QPixmap(); }
@@ -61,7 +71,7 @@ public:
virtual int concurrentJobLimit() const { return 3; } virtual int concurrentJobLimit() const { return 3; }
virtual bool hasCustomDelegate() const { return true; } virtual bool hasCustomDelegate() const { return true; }
virtual void createDelegate( QObject* parent ); virtual void createDelegate( QObject* parent = 0 );
virtual QStyledItemDelegate* customDelegate() const { return m_delegate; } virtual QStyledItemDelegate* customDelegate() const { return m_delegate; }
virtual ACLRegistry::User user() const { return m_user; } virtual ACLRegistry::User user() const { return m_user; }
@@ -69,6 +79,9 @@ public:
signals: signals:
void userDecision( ACLRegistry::User user ); void userDecision( ACLRegistry::User user );
public slots:
void aclResult( ACLRegistry::ACL result );
private: private:
QStyledItemDelegate* m_delegate; QStyledItemDelegate* m_delegate;

View File

@@ -59,8 +59,11 @@ JobStatusDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option,
if ( allowMultiLine ) if ( allowMultiLine )
iconRect.moveTop( opt.rect.top() + opt.rect.height() / 2 - iconRect.height() / 2); iconRect.moveTop( opt.rect.top() + opt.rect.height() / 2 - iconRect.height() / 2);
QPixmap p = index.data( Qt::DecorationRole ).value< QPixmap >(); QPixmap p = index.data( Qt::DecorationRole ).value< QPixmap >();
p = p.scaledToHeight( iconRect.height(), Qt::SmoothTransformation ); if ( !p.isNull() )
painter->drawPixmap( iconRect, p ); {
p = p.scaledToHeight( iconRect.height(), Qt::SmoothTransformation );
painter->drawPixmap( iconRect, p );
}
// draw right column if there is one // draw right column if there is one
const QString rCol = index.data( JobStatusModel::RightColumnRole ).toString(); const QString rCol = index.data( JobStatusModel::RightColumnRole ).toString();

View File

@@ -41,6 +41,7 @@ JobStatusModel::~JobStatusModel()
void void
JobStatusModel::addJob( JobStatusItem* item ) JobStatusModel::addJob( JobStatusItem* item )
{ {
tLog() << Q_FUNC_INFO << "current jobs of item type: " << m_jobTypeCount[ item->type() ] << ", current queue size of item type: " << m_jobQueue[ item->type() ].size();
if ( item->concurrentJobLimit() > 0 ) if ( item->concurrentJobLimit() > 0 )
{ {
if ( m_jobTypeCount[ item->type() ] >= item->concurrentJobLimit() ) if ( m_jobTypeCount[ item->type() ] >= item->concurrentJobLimit() )
@@ -53,6 +54,8 @@ JobStatusModel::addJob( JobStatusItem* item )
m_jobTypeCount[ item->type() ] = currentJobCount; m_jobTypeCount[ item->type() ] = currentJobCount;
} }
tLog() << Q_FUNC_INFO << "new current jobs of item type: " << m_jobTypeCount[ item->type() ];
connect( item, SIGNAL( statusChanged() ), SLOT( itemUpdated() ) ); connect( item, SIGNAL( statusChanged() ), SLOT( itemUpdated() ) );
connect( item, SIGNAL( finished() ), SLOT( itemFinished() ) ); connect( item, SIGNAL( finished() ), SLOT( itemFinished() ) );
@@ -70,7 +73,7 @@ JobStatusModel::addJob( JobStatusItem* item )
} }
} }
qDebug() << "Adding item:" << item; tLog() << Q_FUNC_INFO << "Adding item:" << item;
int currentEndRow = m_items.count(); int currentEndRow = m_items.count();
beginInsertRows( QModelIndex(), currentEndRow, currentEndRow ); beginInsertRows( QModelIndex(), currentEndRow, currentEndRow );
@@ -79,7 +82,7 @@ JobStatusModel::addJob( JobStatusItem* item )
if ( item->hasCustomDelegate() ) if ( item->hasCustomDelegate() )
{ {
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "job has custom delegate"; tLog() << Q_FUNC_INFO << "job has custom delegate";
emit customDelegateJobInserted( currentEndRow, item ); emit customDelegateJobInserted( currentEndRow, item );
} }
} }
@@ -184,6 +187,7 @@ JobStatusModel::itemFinished()
// One less to count, but item is still there // One less to count, but item is still there
const QModelIndex idx = index( indexOf, 0, QModelIndex() ); const QModelIndex idx = index( indexOf, 0, QModelIndex() );
emit dataChanged( idx, idx ); emit dataChanged( idx, idx );
emit refreshDelegates();
return; return;
} }
} }
@@ -200,6 +204,9 @@ JobStatusModel::itemFinished()
if ( item->customDelegate() ) if ( item->customDelegate() )
emit customDelegateJobRemoved( idx ); emit customDelegateJobRemoved( idx );
emit refreshDelegates();
tLog() << Q_FUNC_INFO << "current jobs of item type: " << m_jobTypeCount[ item->type() ] << ", current queue size of item type: " << m_jobQueue[ item->type() ].size();
if ( item->concurrentJobLimit() > 0 ) if ( item->concurrentJobLimit() > 0 )
{ {
int currentJobs = m_jobTypeCount[ item->type() ]; int currentJobs = m_jobTypeCount[ item->type() ];

View File

@@ -49,6 +49,7 @@ public:
signals: signals:
void customDelegateJobInserted( int row, JobStatusItem* item ); void customDelegateJobInserted( int row, JobStatusItem* item );
void customDelegateJobRemoved( int row ); void customDelegateJobRemoved( int row );
void refreshDelegates();
public slots: public slots:
/// Takes ownership of job /// Takes ownership of job

View File

@@ -20,6 +20,7 @@
#include "JobStatusView.h" #include "JobStatusView.h"
#include "Pipeline.h" #include "Pipeline.h"
#include "AclJobItem.h"
#include "JobStatusModel.h" #include "JobStatusModel.h"
#include "JobStatusItem.h" #include "JobStatusItem.h"
#include "JobStatusDelegate.h" #include "JobStatusDelegate.h"
@@ -75,6 +76,9 @@ JobStatusView::JobStatusView( AnimatedSplitter* parent )
new PipelineStatusManager( this ); new PipelineStatusManager( this );
new TransferStatusManager( this ); new TransferStatusManager( this );
new LatchedStatusManager( this ); new LatchedStatusManager( this );
setMouseTracking( true );
m_view->setMouseTracking( true );
} }
@@ -90,27 +94,66 @@ JobStatusView::setModel( JobStatusModel* m )
connect( m_view->model(), SIGNAL( modelReset() ), this, SLOT( checkCount() ) ); connect( m_view->model(), SIGNAL( modelReset() ), this, SLOT( checkCount() ) );
connect( m_view->model(), SIGNAL( customDelegateJobInserted( int, JobStatusItem* ) ), this, SLOT( customDelegateJobInserted( int, JobStatusItem* ) ) ); connect( m_view->model(), SIGNAL( customDelegateJobInserted( int, JobStatusItem* ) ), this, SLOT( customDelegateJobInserted( int, JobStatusItem* ) ) );
connect( m_view->model(), SIGNAL( customDelegateJobRemoved( int ) ), this, SLOT( customDelegateJobRemoved( int ) ) ); connect( m_view->model(), SIGNAL( customDelegateJobRemoved( int ) ), this, SLOT( customDelegateJobRemoved( int ) ) );
connect( m_view->model(), SIGNAL( refreshDelegates() ), this, SLOT( refreshDelegates() ) );
} }
void void
JobStatusView::customDelegateJobInserted( int row, JobStatusItem* item ) JobStatusView::customDelegateJobInserted( int row, JobStatusItem* item )
{ {
tDebug( LOGVERBOSE ) << Q_FUNC_INFO; tLog() << Q_FUNC_INFO << "item is " << item << ", row is " << row;
if ( !item ) if ( !item )
return; return;
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "telling item to create delegate"; tLog() << Q_FUNC_INFO << "telling item to create delegate";
item->createDelegate( m_view ); item->createDelegate( m_view );
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "item delegate is " << item->customDelegate(); tLog() << Q_FUNC_INFO << "item delegate is " << item->customDelegate();
m_view->setItemDelegateForRow( row, item->customDelegate() ); m_view->setItemDelegateForRow( row, item->customDelegate() );
AclJobDelegate* delegate = qobject_cast< AclJobDelegate* >( item->customDelegate() );
if ( delegate )
{
tLog() << Q_FUNC_INFO << "delegate found";
connect( delegate, SIGNAL( update( const QModelIndex& ) ), m_view, SLOT( update( const QModelIndex & ) ) );
connect( delegate, SIGNAL( aclResult( ACLRegistry::ACL ) ), item, SLOT( aclResult( ACLRegistry::ACL ) ) );
delegate->emitSizeHintChanged( m_model->index( row ) );
}
else
tLog() << Q_FUNC_INFO << "delegate was not properly found!";
checkCount();
} }
void void
JobStatusView::customDelegateJobRemoved( int row ) JobStatusView::customDelegateJobRemoved( int row )
{ {
m_view->setItemDelegateForRow( row, m_view->itemDelegate() ); tLog() << Q_FUNC_INFO << "row is " << row;
}
void
JobStatusView::refreshDelegates()
{
tLog() << Q_FUNC_INFO;
int count = m_model->rowCount();
for ( int i = 0; i < count; i++ )
{
tLog() << Q_FUNC_INFO << "checking row " << i;
QModelIndex index = m_model->index( i );
QVariant itemVar = index.data( JobStatusModel::JobDataRole );
if ( !itemVar.canConvert< JobStatusItem* >() || !itemVar.value< JobStatusItem* >() )
{
tLog() << Q_FUNC_INFO << "unable to fetch JobStatusItem* at row " << i;
continue;
}
JobStatusItem* item = itemVar.value< JobStatusItem* >();
if ( item->hasCustomDelegate() )
m_view->setItemDelegateForRow( i, item->customDelegate() );
else
m_view->setItemDelegateForRow( i, m_view->itemDelegate() );
}
checkCount();
} }

View File

@@ -55,6 +55,7 @@ private slots:
void checkCount(); void checkCount();
void customDelegateJobInserted( int row, JobStatusItem* item ); void customDelegateJobInserted( int row, JobStatusItem* item );
void customDelegateJobRemoved( int row ); void customDelegateJobRemoved( int row );
void refreshDelegates();
private: private:
QListView* m_view; QListView* m_view;

View File

@@ -200,9 +200,10 @@ Connection::checkACL()
} }
QString nodeid = property( "nodeid" ).toString(); QString nodeid = property( "nodeid" ).toString();
QString bareName = name().left( name().indexOf( "/" ) );
tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Checking ACL for" << name(); tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "Checking ACL for" << name();
connect( ACLRegistry::instance(), SIGNAL( aclResult( QString, QString, ACLRegistry::ACL ) ), this, SLOT( checkACLResult( QString, QString, ACLRegistry::ACL ) ), Qt::QueuedConnection ); connect( ACLRegistry::instance(), SIGNAL( aclResult( QString, QString, ACLRegistry::ACL ) ), this, SLOT( checkACLResult( QString, QString, ACLRegistry::ACL ) ), Qt::QueuedConnection );
QMetaObject::invokeMethod( ACLRegistry::instance(), "isAuthorizedUser", Qt::QueuedConnection, Q_ARG( QString, nodeid ), Q_ARG( QString, name() ), Q_ARG( ACLRegistry::ACL, ACLRegistry::NotFound ) ); QMetaObject::invokeMethod( ACLRegistry::instance(), "isAuthorizedUser", Qt::QueuedConnection, Q_ARG( QString, nodeid ), Q_ARG( QString, bareName ), Q_ARG( ACLRegistry::ACL, ACLRegistry::NotFound ) );
} }

View File

@@ -535,6 +535,8 @@ Servent::connectToPeer( const QString& ha, int port, const QString &key, const Q
if( id.length() ) if( id.length() )
conn->setId( id ); conn->setId( id );
conn->setProperty( "nodeid", id );
connectToPeer( ha, port, key, conn ); connectToPeer( ha, port, key, conn );
} }

View File

@@ -169,6 +169,11 @@ SipHandler::onSipInfo( const QString& peerId, const SipInfo& info )
{ {
tDebug() << Q_FUNC_INFO << "SIP Message:" << peerId << info; tDebug() << Q_FUNC_INFO << "SIP Message:" << peerId << info;
QString barePeerId = peerId.left( peerId.indexOf( "/" ) );
//FIXME: We should probably be using barePeerId in the connectToPeer call below.
//But, verify this doesn't cause any problems (there is still a uniquename after all)
/* /*
If only one party is externally visible, connection is obvious If only one party is externally visible, connection is obvious
If both are, peer with lowest IP address initiates the connection. If both are, peer with lowest IP address initiates the connection.
@@ -199,7 +204,7 @@ SipHandler::onSipInfo( const QString& peerId, const SipInfo& info )
m_peersSipInfos.insert( peerId, info ); m_peersSipInfos.insert( peerId, info );
} }
void SipHandler::onSoftwareVersion(const QString& peerId, const QString& versionString) void SipHandler::onSoftwareVersion( const QString& peerId, const QString& versionString )
{ {
m_peersSoftwareVersions.insert( peerId, versionString ); m_peersSoftwareVersions.insert( peerId, versionString );
} }

View File

@@ -443,6 +443,55 @@ prepareStyleOption( QStyleOptionViewItemV4* option, const QModelIndex& index, Pl
} }
void
drawRoundedButton( QPainter* painter, const QRect& btnRect, const QColor& color, const QColor &gradient1bottom, const QColor& gradient2top, const QColor& gradient2bottom )
{
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 ( gradient1bottom.isValid() )
{
g.setColorAt( 0, color );
g.setColorAt( 0.5, gradient1bottom );
painter->fillPath( btnPath, g );
}
else
painter->fillPath( btnPath, color );
//painter->setPen( bg.darker() );
//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 ( gradient2top.isValid() && gradient2bottom.isValid() )
{
g.setColorAt( 0, gradient2top );
g.setColorAt( 0.5, gradient2bottom );
painter->fillPath( btnPath, g );
}
else
painter->fillPath( btnPath, color );
}
void void
styleScrollBar( QScrollBar* scrollBar ) styleScrollBar( QScrollBar* scrollBar )
{ {

View File

@@ -22,6 +22,8 @@
#include <QSize> #include <QSize>
#include <QModelIndex> #include <QModelIndex>
#include <QColor>
#include <QRect>
#include <QTextOption> #include <QTextOption>
#include "TomahawkUtils.h" #include "TomahawkUtils.h"
@@ -30,7 +32,6 @@
class PlayableItem; class PlayableItem;
class QStyleOptionViewItemV4; class QStyleOptionViewItemV4;
class QPainter; class QPainter;
class QColor;
class QPixmap; class QPixmap;
class QLayout; class QLayout;
class QPalette; class QPalette;
@@ -60,7 +61,9 @@ namespace TomahawkUtils
DLLEXPORT QPixmap defaultPixmap( ImageType type, ImageMode mode = TomahawkUtils::Original, const QSize& size = QSize( 0, 0 ) ); DLLEXPORT QPixmap defaultPixmap( ImageType type, ImageMode mode = TomahawkUtils::Original, const QSize& size = QSize( 0, 0 ) );
DLLEXPORT void prepareStyleOption( QStyleOptionViewItemV4* option, const QModelIndex& index, PlayableItem* item ); DLLEXPORT void prepareStyleOption( QStyleOptionViewItemV4* option, const QModelIndex& index, PlayableItem* item );
DLLEXPORT void drawRoundedButton( QPainter* painter, const QRect& btnRect, const QColor& color, const QColor &gradient1bottom = QColor(), const QColor& gradient2top = QColor(), const QColor& gradient2bottom = QColor() );
DLLEXPORT void styleScrollBar( QScrollBar* scrollBar ); DLLEXPORT void styleScrollBar( QScrollBar* scrollBar );
} }