1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-08-10 08:04:25 +02:00

Merge remote branch 'origin/master' into leos-crash

Conflicts:
	src/sip/twitter/twitter.cpp
	src/sip/twitter/twitterconfigwidget.cpp
This commit is contained in:
Jeff Mitchell
2011-05-03 21:58:24 -04:00
63 changed files with 3297 additions and 611 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 489 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 757 B

View File

@@ -82,7 +82,7 @@ public:
void init();
static TomahawkApp* instance();
SipHandler* sipHandler() { return m_sipHandler; }
SipHandler* sipHandler();
XMPPBot* xmppBot() { return m_xmppBot; }
#ifndef TOMAHAWK_HEADLESS
@@ -119,7 +119,6 @@ private:
Database* m_database;
ScanManager *m_scanManager;
AudioEngine* m_audioEngine;
SipHandler* m_sipHandler;
Servent* m_servent;
Tomahawk::InfoSystem::InfoSystem* m_infoSystem;
XMPPBot* m_xmppBot;

View File

@@ -79,6 +79,13 @@
<file>./data/images/add.png</file>
<file>./data/images/recently-played.png</file>
<file>./data/images/supercollection.png</file>
<file>./data/images/sipplugin-online.png</file>
<file>./data/images/sipplugin-offline.png</file>
<file>./data/images/advanced-settings.png</file>
<file>./data/images/account-settings.png</file>
<file>./data/images/music-settings.png</file>
<file>./data/images/resolvers-settings.png</file>
<file>./data/images/lastfm-settings.png</file>
<file>./data/topbar-radiobuttons.css</file>
<file>./data/icons/tomahawk-icon-16x16.png</file>
<file>./data/icons/tomahawk-icon-32x32.png</file>

View File

@@ -64,6 +64,8 @@ SET( tomahawkSourcesGui ${tomahawkSourcesGui}
tomahawktrayicon.cpp
audiocontrols.cpp
settingsdialog.cpp
configdelegatebase.cpp
sipconfigdelegate.cpp
resolverconfigdelegate.cpp
resolversmodel.cpp
tomahawkwindow.cpp
@@ -104,15 +106,18 @@ SET( tomahawkHeadersGui ${tomahawkHeadersGui}
tomahawktrayicon.h
audiocontrols.h
settingsdialog.h
configdelegatebase.h
resolverconfigdelegate.h
sipconfigdelegate.h
resolversmodel.h
resolverconfigwrapper.h
delegateconfigwrapper.h
tomahawkwindow.h
)
SET( tomahawkUI ${tomahawkUI}
tomahawkwindow.ui
settingsdialog.ui
stackedsettingsdialog.ui
proxydialog.ui
audiocontrols.ui

120
src/configdelegatebase.cpp Normal file
View File

@@ -0,0 +1,120 @@
/*
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 "utils/tomahawkutils.h"
#include <QPainter>
#include <QApplication>
#include <QMouseEvent>
ConfigDelegateBase::ConfigDelegateBase ( QObject* parent )
: QStyledItemDelegate ( parent )
, m_configPressed( false )
{
}
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
{
m_checkRect = opt.rect;
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;
topt.state = m_configPressed ? QStyle::State_On : QStyle::State_Raised;
if( opt.state & QStyle::State_MouseOver || m_configPressed )
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 = false;
QMouseEvent* me = static_cast< QMouseEvent* >( event );
if( me->button() != Qt::LeftButton || !m_checkRect.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 = true;
emit configPressed( index );
return true;
}
}
return QStyledItemDelegate::editorEvent( event, model, option, index );
}

54
src/configdelegatebase.h Normal file
View File

@@ -0,0 +1,54 @@
/*
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 CONFIGDELEGATEBASE_H
#define CONFIGDELEGATEBASE_H
#include "dllmacro.h"
#include <QStyledItemDelegate>
#define PADDING 4
class QPainter;
class DLLEXPORT ConfigDelegateBase : public QStyledItemDelegate
{
Q_OBJECT
public:
ConfigDelegateBase( QObject* parent = 0 );
virtual QSize sizeHint ( const QStyleOptionViewItem& option, const QModelIndex& index ) const;
virtual bool editorEvent ( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index );
// 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;
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:
mutable QRect m_checkRect;
mutable QRect m_configRect;
bool m_configPressed;
};
#endif // CONFIGDELEGATEBASE_H

View File

@@ -22,14 +22,16 @@
#include <QDialogButtonBox>
#include <QVBoxLayout>
class ResolverConfigWrapper : public QDialog
class DelegateConfigWrapper : public QDialog
{
Q_OBJECT
public:
ResolverConfigWrapper( QWidget* conf, const QString& title, QWidget* parent ) : QDialog( parent ), m_widget( conf )
DelegateConfigWrapper( QWidget* conf, const QString& title, QWidget* parent ) : QDialog( parent ), m_widget( conf )
{
setWindowTitle( title );
m_widget->setVisible( true );
m_widget->setWindowFlags( Qt::Sheet );
setWindowTitle( title );
QVBoxLayout* v = new QVBoxLayout( this );
v->addWidget( m_widget );
@@ -46,6 +48,7 @@ public slots:
// let the config widget live to see another day
layout()->removeWidget( m_widget );
m_widget->setParent( 0 );
m_widget->setVisible( false );
QDialogButtonBox* buttons = qobject_cast< QDialogButtonBox* >( sender() );
if( buttons->standardButton( b ) == QDialogButtonBox::Ok )
@@ -59,6 +62,7 @@ public slots:
{
layout()->removeWidget( m_widget );
m_widget->setParent( 0 );
m_widget->setVisible( false );
}
private:

View File

@@ -33,6 +33,7 @@ set( libSources
sip/SipPlugin.cpp
sip/SipHandler.cpp
sip/SipModel.cpp
audio/audioengine.cpp
@@ -193,6 +194,7 @@ set( libHeaders
sip/SipPlugin.h
sip/SipHandler.h
sip/SipModel.h
audio/audioengine.h

View File

@@ -42,6 +42,8 @@ SipHandler* SipHandler::s_instance = 0;
SipHandler* SipHandler::instance()
{
if( s_instance == 0 )
s_instance = new SipHandler( 0 );
return s_instance;
}
@@ -51,7 +53,7 @@ SipHandler::SipHandler( QObject* parent )
{
s_instance = this;
loadPlugins( findPlugins() );
loadPluginFactories( findPluginFactories() );
connect( TomahawkSettings::instance(), SIGNAL( changed() ), SLOT( onSettingsChanged() ) );
}
@@ -59,14 +61,7 @@ SipHandler::SipHandler( QObject* parent )
SipHandler::~SipHandler()
{
disconnectPlugins();
}
QList< SipPlugin* >
SipHandler::plugins() const
{
return m_plugins;
disconnectAll();
}
const QPixmap SipHandler::avatar( const QString& name ) const
@@ -95,7 +90,7 @@ SipHandler::onSettingsChanged()
QStringList
SipHandler::findPlugins()
SipHandler::findPluginFactories()
{
QStringList paths;
QList< QDir > pluginDirs;
@@ -137,7 +132,7 @@ SipHandler::findPlugins()
void
SipHandler::loadPlugins( const QStringList& paths )
SipHandler::loadPluginFactories( const QStringList& paths )
{
foreach ( QString fileName, paths )
{
@@ -145,13 +140,67 @@ SipHandler::loadPlugins( const QStringList& paths )
continue;
qDebug() << "Trying to load plugin:" << fileName;
loadPlugin( fileName );
loadPluginFactory( fileName );
}
}
SipPlugin*
SipHandler::createPlugin( const QString& factoryId )
{
Q_ASSERT( m_pluginFactories.contains( factoryId ) );
SipPlugin* sip = m_pluginFactories[ factoryId ]->createPlugin();
hookUpPlugin( sip );
emit pluginAdded( sip );
return sip;
}
SipPlugin*
SipHandler::loadPlugin( const QString& pluginId )
{
QString factoryName = factoryFromId( pluginId );
Q_ASSERT( m_pluginFactories.contains( factoryName ) );
SipPlugin* sip = m_pluginFactories[ factoryName ]->createPlugin( pluginId );
hookUpPlugin( sip );
// caller responsible for calling pluginAdded()
return sip;
}
void
SipHandler::removePlugin( SipPlugin* p )
{
p->disconnectPlugin();
m_allPlugins.removeAll( p );
m_enabledPlugins.removeAll( p );
TomahawkSettings::instance()->removeSipPlugin( p->pluginId() );
emit pluginRemoved( p );
}
void
SipHandler::loadPlugin( const QString& path )
SipHandler::hookUpPlugin( SipPlugin* sip )
{
QObject::connect( sip, SIGNAL( peerOnline( QString ) ), SLOT( onPeerOnline( QString ) ) );
QObject::connect( sip, SIGNAL( peerOffline( QString ) ), SLOT( onPeerOffline( QString ) ) );
QObject::connect( sip, SIGNAL( msgReceived( QString, QString ) ), SLOT( onMessage( QString, QString ) ) );
QObject::connect( sip, SIGNAL( error( int, QString ) ), SLOT( onError( int, QString ) ) );
QObject::connect( sip, SIGNAL( stateChanged( SipPlugin::ConnectionState ) ), SLOT( onStateChanged( SipPlugin::ConnectionState ) ) );
QObject::connect( sip, SIGNAL( avatarReceived( QString, QPixmap ) ), SLOT( onAvatarReceived( QString, QPixmap ) ) );
QObject::connect( sip, SIGNAL( avatarReceived( QPixmap ) ), SLOT( onAvatarReceived( QPixmap ) ) );
}
void
SipHandler::loadPluginFactory( const QString& path )
{
QPluginLoader loader( path );
QObject* plugin = loader.instance();
@@ -160,37 +209,24 @@ SipHandler::loadPlugin( const QString& path )
qDebug() << "Error loading plugin:" << loader.errorString();
}
SipPlugin* sip = qobject_cast<SipPlugin*>(plugin);
if ( sip )
SipPluginFactory* sipfactory = qobject_cast<SipPluginFactory*>(plugin);
if ( sipfactory )
{
if ( pluginLoaded( sip->name() ) )
qDebug() << "Loaded plugin factory:" << loader.fileName() << sipfactory->factoryId() << sipfactory->prettyName();
m_pluginFactories[ sipfactory->factoryId() ] = sipfactory;
} else
{
qDebug() << "Plugin" << sip->name() << "already loaded! Not loading:" << loader.fileName();
return;
}
qDebug() << "Loaded plugin:" << loader.fileName();
QObject::connect( sip, SIGNAL( peerOnline( QString ) ), SLOT( onPeerOnline( QString ) ) );
QObject::connect( sip, SIGNAL( peerOffline( QString ) ), SLOT( onPeerOffline( QString ) ) );
QObject::connect( sip, SIGNAL( msgReceived( QString, QString ) ), SLOT( onMessage( QString, QString ) ) );
QObject::connect( sip, SIGNAL( connected() ), SIGNAL( connected() ) );
QObject::connect( sip, SIGNAL( disconnected() ), SIGNAL( disconnected() ) );
QObject::connect( sip, SIGNAL( error( int, QString ) ), SLOT( onError( int, QString ) ) );
QObject::connect( sip, SIGNAL( avatarReceived( QString, QPixmap ) ), SLOT( onAvatarReceived( QString, QPixmap ) ) );
QObject::connect( sip, SIGNAL( avatarReceived( QPixmap ) ), SLOT( onAvatarReceived( QPixmap ) ) );
m_plugins << sip;
qDebug() << "Loaded invalid plugin.." << loader.fileName();
}
}
bool
SipHandler::pluginLoaded( const QString& name ) const
SipHandler::pluginLoaded( const QString& pluginId ) const
{
foreach( SipPlugin* plugin, m_plugins )
foreach( SipPlugin* plugin, m_allPlugins )
{
if ( plugin->name() == name )
if ( plugin->pluginId() == pluginId )
return true;
}
@@ -201,15 +237,111 @@ SipHandler::pluginLoaded( const QString& name ) const
void
SipHandler::checkSettings()
{
foreach( SipPlugin* sip, m_plugins )
foreach( SipPlugin* sip, m_allPlugins )
{
sip->checkSettings();
}
}
void
SipHandler::addSipPlugin( SipPlugin* p, bool enabled, bool startup )
{
m_allPlugins << p;
if ( enabled )
{
p->connectPlugin( startup );
m_enabledPlugins << p;
}
emit pluginAdded( p );
}
void
SipHandler::connectPlugins( bool startup, const QString &pluginName )
SipHandler::removeSipPlugin( SipPlugin* p )
{
p->disconnectPlugin();
emit pluginRemoved( p );
// emit first so sipmodel can find the indexOf
TomahawkSettings::instance()->removeSipPlugin( p->pluginId() );
m_allPlugins.removeAll( p );
m_enabledPlugins.removeAll( p );
}
bool
SipHandler::hasPluginType( const QString& factoryId ) const
{
foreach( SipPlugin* p, m_allPlugins ) {
if( factoryFromId( p->pluginId() ) == factoryId )
return true;
}
return false;
}
void
SipHandler::loadFromConfig( bool startup )
{
QStringList pluginIds = TomahawkSettings::instance()->sipPlugins();
QStringList enabled = TomahawkSettings::instance()->enabledSipPlugins();
foreach( const QString& pluginId, pluginIds )
{
QString pluginFactory = factoryFromId( pluginId );
if( m_pluginFactories.contains( pluginFactory ) )
{
SipPlugin* p = loadPlugin( pluginId );
addSipPlugin( p, enabled.contains( pluginId ), startup );
}
}
m_connected = true;
}
void
SipHandler::connectAll()
{
foreach( SipPlugin* sip, m_enabledPlugins )
{
sip->connectPlugin();
}
m_connected = true;
}
void
SipHandler::disconnectAll()
{
foreach( SipPlugin* p, m_connectedPlugins )
p->disconnectPlugin();
SourceList::instance()->removeAllRemote();
m_connected = false;
}
void
SipHandler::disablePlugin( SipPlugin* p )
{
Q_ASSERT( m_enabledPlugins.contains( p ) );
TomahawkSettings::instance()->disableSipPlugin( p->pluginId() );
p->disconnectPlugin();
m_enabledPlugins.removeAll( p );
}
void
SipHandler::enablePlugin( SipPlugin* p )
{
Q_ASSERT( !m_enabledPlugins.contains( p ) );
p->connectPlugin();
TomahawkSettings::instance()->enableSipPlugin( p->pluginId() );
m_enabledPlugins << p;
}
void
SipHandler::connectPlugin( bool startup, const QString &pluginId )
{
#ifndef TOMAHAWK_HEADLESS
if ( !TomahawkSettings::instance()->acceptedLegalWarning() )
@@ -226,33 +358,49 @@ SipHandler::connectPlugins( bool startup, const QString &pluginName )
TomahawkSettings::instance()->setAcceptedLegalWarning( true );
}
#endif
foreach( SipPlugin* sip, m_plugins )
foreach( SipPlugin* sip, m_allPlugins )
{
if ( pluginName.isEmpty() || ( !pluginName.isEmpty() && sip->name() == pluginName ) )
if ( sip->pluginId() == pluginId )
{
Q_ASSERT( m_enabledPlugins.contains( sip ) ); // make sure the plugin we're connecting is enabled. should always be the case
sip->connectPlugin( startup );
}
if ( pluginName.isEmpty() )
{
m_connected = true;
}
}
void
SipHandler::disconnectPlugins( const QString &pluginName )
SipHandler::disconnectPlugin( const QString &pluginName )
{
foreach( SipPlugin* sip, m_plugins )
foreach( SipPlugin* sip, m_connectedPlugins )
{
if ( pluginName.isEmpty() || ( !pluginName.isEmpty() && sip->name() == pluginName ) )
if ( sip->name() == pluginName )
sip->disconnectPlugin();
}
if ( pluginName.isEmpty() )
{
SourceList::instance()->removeAllRemote();
m_connected = false;
}
QList< SipPlugin* >
SipHandler::allPlugins() const
{
return m_allPlugins;
}
QList< SipPlugin* >
SipHandler::enabledPlugins() const
{
return m_enabledPlugins;
}
QList< SipPlugin* >
SipHandler::connectedPlugins() const
{
return m_connectedPlugins;
}
QList< SipPluginFactory* >
SipHandler::pluginFactories() const
{
return m_pluginFactories.values();
}
@@ -260,9 +408,9 @@ void
SipHandler::toggleConnect()
{
if( m_connected )
disconnectPlugins();
disconnectAll();
else
connectPlugins();
connectAll();
}
@@ -368,20 +516,43 @@ SipHandler::onMessage( const QString& from, const QString& msg )
void
SipHandler::onError( int code, const QString& msg )
{
qWarning() << "Failed to connect to SIP:" << code << msg;
SipPlugin* sip = qobject_cast< SipPlugin* >( sender() );
Q_ASSERT( sip );
qWarning() << "Failed to connect to SIP:" << sip->accountName() << code << msg;
if ( code == SipPlugin::AuthError )
{
emit authError();
emit authError( sip );
}
else
{
SipPlugin* sip = qobject_cast<SipPlugin*>(sender());
QTimer::singleShot( 10000, sip, SLOT( connectPlugin() ) );
}
}
void SipHandler::onAvatarReceived( const QString& from, const QPixmap& avatar )
void
SipHandler::onStateChanged( SipPlugin::ConnectionState state )
{
SipPlugin* sip = qobject_cast< SipPlugin* >( sender() );
Q_ASSERT( sip );
if ( sip->connectionState() == SipPlugin::Disconnected )
{
m_connectedPlugins.removeAll( sip );
emit disconnected( sip );
} else if ( sip->connectionState() == SipPlugin::Connected )
{
m_connectedPlugins.removeAll( sip );
emit disconnected( sip );
}
emit stateChanged( sip, state );
}
void
SipHandler::onAvatarReceived( const QString& from, const QPixmap& avatar )
{
qDebug() << Q_FUNC_INFO << "Set avatar on source for " << from;
Q_ASSERT(!avatar.isNull());
@@ -413,8 +584,23 @@ void SipHandler::onAvatarReceived( const QString& from, const QPixmap& avatar )
}
}
void SipHandler::onAvatarReceived( const QPixmap& avatar )
void
SipHandler::onAvatarReceived( const QPixmap& avatar )
{
qDebug() << Q_FUNC_INFO << "Set own avatar on MyCollection";
SourceList::instance()->getLocal()->setAvatar( avatar );
}
QString
SipHandler::factoryFromId( const QString& pluginId ) const
{
return pluginId.split( "_" ).first();
}
SipPluginFactory*
SipHandler::factoryFromPlugin( SipPlugin* p ) const
{
QString factoryId = factoryFromId( p->pluginId() );
return m_pluginFactories.value( factoryId, 0 );
}

View File

@@ -38,28 +38,56 @@ public:
SipHandler( QObject* parent );
~SipHandler();
QList< SipPlugin* > plugins() const;
QList< SipPluginFactory* > pluginFactories() const;
QList< SipPlugin* > allPlugins() const;
QList< SipPlugin* > enabledPlugins() const;
QList< SipPlugin* > connectedPlugins() const;
void loadFromConfig( bool startup = false );
void addSipPlugin( SipPlugin* p, bool enable = true, bool connectImmediately = true );
void removeSipPlugin( SipPlugin* p );
bool hasPluginType( const QString& factoryId ) const;
SipPluginFactory* factoryFromPlugin( SipPlugin* p ) const;
const QPixmap avatar( const QString& name ) const;
public slots:
void addContact( const QString& id ) { qDebug() << Q_FUNC_INFO << id; }
void checkSettings();
void connectPlugins( bool startup = false, const QString &pluginName = QString() );
void disconnectPlugins( const QString &pluginName = QString() );
void enablePlugin( SipPlugin* p );
void disablePlugin( SipPlugin* p );
void connectPlugin( bool startup = false, const QString &pluginId = QString() );
void disconnectPlugin( const QString &pluginId = QString() );
void connectAll();
void disconnectAll();
void toggleConnect();
// create a new plugin of the given name. the name is the value returned in SipPluginFactory::pluginName
// be default sip plugins are NOt connected when created
SipPlugin* createPlugin( const QString& factoryName );
// load a plugin with the given id
SipPlugin* loadPlugin( const QString& pluginId );
void removePlugin( SipPlugin* p );
signals:
void connected();
void disconnected();
void authError();
void connected( SipPlugin* );
void disconnected( SipPlugin* );
void authError( SipPlugin* );
void stateChanged( SipPlugin* p, SipPlugin::ConnectionState state );
void pluginAdded( SipPlugin* p );
void pluginRemoved( SipPlugin* p );
private slots:
void onMessage( const QString&, const QString& );
void onPeerOffline( const QString& );
void onPeerOnline( const QString& );
void onError( int code, const QString& msg );
void onStateChanged( SipPlugin::ConnectionState );
void onSettingsChanged();
@@ -73,13 +101,18 @@ private slots:
private:
static SipHandler *s_instance;
QStringList findPlugins();
bool pluginLoaded( const QString& name ) const;
QStringList findPluginFactories();
bool pluginLoaded( const QString& pluginId ) const;
void hookUpPlugin( SipPlugin* p );
void loadPlugins( const QStringList& paths );
void loadPlugin( const QString& path );
void loadPluginFactories( const QStringList& paths );
void loadPluginFactory( const QString& path );
QString factoryFromId( const QString& pluginId ) const;
QList< SipPlugin* > m_plugins;
QHash< QString, SipPluginFactory* > m_pluginFactories;
QList< SipPlugin* > m_allPlugins;
QList< SipPlugin* > m_enabledPlugins;
QList< SipPlugin* > m_connectedPlugins;
bool m_connected;

View File

@@ -0,0 +1,213 @@
/*
Copyright (C) 2011 Leo Franchi <lfranchi@kde.org>
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 "SipModel.h"
#include "tomahawksettings.h"
#include "tomahawk/tomahawkapp.h"
#include "sip/SipHandler.h"
#include "sip/SipPlugin.h"
SipModel::SipModel( QObject* parent )
: QAbstractItemModel( parent )
{
connect( SipHandler::instance(), SIGNAL( stateChanged( SipPlugin*, SipPlugin::ConnectionState ) ), this, SLOT( pluginStateChanged( SipPlugin* ) ) );
connect( SipHandler::instance(), SIGNAL( pluginAdded( SipPlugin* ) ), this, SLOT( pluginAdded( SipPlugin* ) ) );
connect( SipHandler::instance(), SIGNAL( pluginRemoved( SipPlugin* ) ), this, SLOT( pluginRemoved( SipPlugin* ) ) );
// TODO disable inline factories for now
/*
foreach( SipPluginFactory* f, SipHandler::instance()->pluginFactories() ) {
if( f->isCreatable() )
m_factories << f;
} */
}
SipModel::~SipModel()
{
}
QVariant
SipModel::data( const QModelIndex& index, int role ) const
{
if( !index.isValid() )
return QVariant();
if( !index.parent().isValid() && index.row() == SipHandler::instance()->allPlugins().count() ) { // last row, this is the factory
if( role == Qt::DisplayRole )
return tr( "Add New Account..." );
else if( role == FactoryRole )
return true;
else
return QVariant();
}
if( !index.parent().isValid() ) { // account
QList< SipPlugin* > plugins = SipHandler::instance()->allPlugins();
Q_ASSERT( index.row() <= plugins.size() );
SipPlugin* p = plugins[ index.row() ];
switch( role )
{
case Qt::DisplayRole:
case SipModel::PluginName:
return p->accountName();
case SipModel::ConnectionStateRole:
return p->connectionState();
case SipModel::HasConfig:
return ( p->configWidget() != 0 );
case SipModel::FactoryRole:
return false;
case Qt::DecorationRole:
return p->icon();
case SipModel::SipPluginData:
return QVariant::fromValue< QObject* >( p );
case Qt::CheckStateRole:
return SipHandler::instance()->enabledPlugins().contains( p ) ? Qt::Checked : Qt::Unchecked;
default:
return QVariant();
}
}
if( index.parent().isValid() ) { // this is a factory type
SipPluginFactory* p = m_factories.at( index.row() );
switch( role )
{
case Qt::DisplayRole:
return p->prettyName();
case SipModel::FactoryItemRole:
return true;
case SipModel::FactoryItemIcon:
return p->icon();
case SipModel::SipPluginFactoryData:
return QVariant::fromValue< QObject* >( p );
default:
return QVariant();
}
}
return QVariant();
}
bool
SipModel::setData( const QModelIndex& index, const QVariant& value, int role )
{
Q_ASSERT( index.isValid() && index.row() <= SipHandler::instance()->allPlugins().count() );
if( role == Qt::CheckStateRole ) {
Qt::CheckState state = static_cast< Qt::CheckState >( value.toInt() );
QList< SipPlugin* > plugins = SipHandler::instance()->allPlugins();
SipPlugin* p = plugins[ index.row() ];
if( state == Qt::Checked && !SipHandler::instance()->enabledPlugins().contains( p ) ) {
SipHandler::instance()->enablePlugin( p );
} else if( state == Qt::Unchecked ) {
SipHandler::instance()->disablePlugin( p );
}
dataChanged( index, index );
return true;
}
return false;
}
QModelIndex
SipModel::index( int row, int column, const QModelIndex& parent ) const
{
if( !parent.isValid() )
return hasIndex( row, column, parent ) ? createIndex( row, column, 0 ) : QModelIndex();
// qDebug() << "Creating index for non-top level row!";
// it's a child of the Add Account, e.g. a factory
if( hasIndex( row, column, parent ) ) {
return createIndex( row, column, 1 /* magic */ );
}
return QModelIndex();
}
QModelIndex
SipModel::parent( const QModelIndex& child ) const
{
if( !child.isValid() )
return QModelIndex();
if( child.internalId() == 1 ) {
return index( SipHandler::instance()->allPlugins().size(), 0, QModelIndex() );
}
return QModelIndex();
}
int
SipModel::rowCount( const QModelIndex& parent ) const
{
if( !parent.isValid() ) // invalid root node
return SipHandler::instance()->allPlugins().size() /* TODO inline factories disabled + 1*/;
if( parent.isValid() && !parent.parent().isValid() ) { // top level item
if( parent.row() == SipHandler::instance()->allPlugins().count() ) {// last row, this is the factory
return m_factories.count();
}
}
return 0;
}
int
SipModel::columnCount(const QModelIndex& parent) const
{
Q_UNUSED( parent );
return 1;
}
Qt::ItemFlags
SipModel::flags( const QModelIndex& index ) const
{
if( index.data( SipModel::FactoryRole ).toBool() || index.data( SipModel::FactoryItemRole ).toBool() )
return QAbstractItemModel::flags( index ) & ~Qt::ItemIsSelectable;
return QAbstractItemModel::flags( index ) | Qt::ItemIsUserCheckable;
}
void
SipModel::pluginAdded( SipPlugin* p )
{
// we assume sip plugins are added at the end of the list.
Q_ASSERT( SipHandler::instance()->allPlugins().last() == p );
int size = SipHandler::instance()->allPlugins().count() - 1;
beginInsertRows( QModelIndex(), size, size );
endInsertRows();
}
void
SipModel::pluginRemoved( SipPlugin* p )
{
int idx = SipHandler::instance()->allPlugins().indexOf( p );
beginRemoveRows( QModelIndex(), idx, idx );
endRemoveRows();
}
void
SipModel::pluginStateChanged( SipPlugin* p )
{
int at = SipHandler::instance()->allPlugins().indexOf( p );
QModelIndex idx = index( at, 0, QModelIndex() );
emit dataChanged( idx, idx );
}

View File

@@ -0,0 +1,67 @@
/*
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 2011 Leo Franchi <lfranchi@kde.org>
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 SIPMODEL_H
#define SIPMODEL_H
#include "dllmacro.h"
#include <QModelIndex>
#include <QStringList>
class SipPluginFactory;
class SipPlugin;
class DLLEXPORT SipModel : public QAbstractItemModel
{
Q_OBJECT
public:
enum Roles {
PluginName = Qt::UserRole + 15,
ConnectionStateRole = Qt::UserRole + 17,
HasConfig = Qt::UserRole + 18,
FactoryRole = Qt::UserRole + 19,
ErrorString = Qt::UserRole + 20,
FactoryItemRole = Qt::UserRole + 21,
FactoryItemIcon = Qt::UserRole + 22,
SipPluginData = Qt::UserRole + 23,
SipPluginFactoryData = Qt::UserRole + 24
};
explicit SipModel( QObject* parent = 0 );
virtual ~SipModel();
virtual QModelIndex index ( int row, int column, const QModelIndex& parent = QModelIndex() ) const;
virtual QModelIndex parent ( const QModelIndex& child ) const;
virtual QVariant data( const QModelIndex& index, int role = Qt::DisplayRole ) const;
virtual int rowCount( const QModelIndex& parent = QModelIndex() ) const;
virtual int columnCount( const QModelIndex& parent ) const;
virtual Qt::ItemFlags flags(const QModelIndex& index) const;
virtual bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole);
private slots:
void pluginAdded( SipPlugin* p );
void pluginRemoved( SipPlugin* p );
void pluginStateChanged( SipPlugin* p );
private:
QList< SipPluginFactory* > m_factories;
};
#endif // SIPMODEL_H

View File

@@ -17,7 +17,28 @@
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#include <sip/SipPlugin.h>
#include "sip/SipPlugin.h"
#include <QUuid>
QString
SipPluginFactory::generateId()
{
QString uniq = QUuid::createUuid().toString().mid( 1, 8 );
return factoryId() + "_" + uniq;
}
SipPlugin::SipPlugin( const QString& pluginId, QObject* parent )
: QObject( parent )
, m_pluginId( pluginId )
{
}
QString SipPlugin::pluginId() const
{
return m_pluginId;
}
QMenu*
@@ -33,6 +54,18 @@ SipPlugin::configWidget()
return 0;
}
QString
SipPlugin::errorMessage() const
{
return QString();
}
QIcon
SipPlugin::icon() const
{
return QIcon();
}
void
SipPlugin::setProxy( const QNetworkProxy& proxy )
{

View File

@@ -28,21 +28,53 @@
#include "dllmacro.h"
class SipPlugin;
class DLLEXPORT SipPluginFactory : public QObject
{
Q_OBJECT
public:
SipPluginFactory() {}
virtual ~SipPluginFactory() {}
// display name for plugin
virtual QString prettyName() const = 0;
// internal name
virtual QString factoryId() const = 0;
// if the user can create multiple
virtual QIcon icon() const { return QIcon(); }
virtual bool isUnique() const { return false; }
virtual SipPlugin* createPlugin( const QString& pluginId = QString() ) = 0;
protected:
QString generateId();
};
class DLLEXPORT SipPlugin : public QObject
{
Q_OBJECT
public:
enum SipErrorCode { AuthError, ConnectionError }; // Placeholder for errors, to be defined
enum ConnectionState { Disconnected, Connecting, Connected };
explicit SipPlugin( const QString& pluginId, QObject* parent = 0 );
virtual ~SipPlugin() {}
virtual bool isValid() = 0;
virtual const QString name() = 0;
virtual const QString friendlyName() = 0;
virtual const QString accountName() = 0;
// plugin id is "pluginfactoryname_someuniqueid". get it from SipPluginFactory::generateId
QString pluginId() const;
virtual bool isValid() const = 0;
virtual const QString name() const = 0;
virtual const QString friendlyName() const = 0;
virtual const QString accountName() const = 0;
virtual ConnectionState connectionState() const = 0;
virtual QString errorMessage() const;
virtual QMenu* menu();
virtual QWidget* configWidget();
virtual void saveConfig() {} // called when the widget has been edited
virtual QIcon icon() const;
public slots:
virtual bool connectPlugin( bool startup = false ) = 0;
@@ -56,8 +88,7 @@ public slots:
signals:
void error( int, const QString& );
void connected();
void disconnected();
void stateChanged( SipPlugin::ConnectionState state );
void peerOnline( const QString& );
void peerOffline( const QString& );
@@ -72,8 +103,11 @@ signals:
void addMenu( QMenu* menu );
void removeMenu( QMenu* menu );
private:
QString m_pluginId;
};
Q_DECLARE_INTERFACE( SipPlugin, "tomahawk.Sip/1.0" )
Q_DECLARE_INTERFACE( SipPluginFactory, "tomahawk.SipFactory/1.0" )
#endif

View File

@@ -25,8 +25,9 @@
#include <QDir>
#include <QDebug>
#include "sip/SipHandler.h"
#define VERSION 2
#define VERSION 3
TomahawkSettings* TomahawkSettings::s_instance = 0;
@@ -46,6 +47,7 @@ TomahawkSettings::TomahawkSettings( QObject* parent )
if( !contains( "configversion") )
{
setValue( "configversion", VERSION );
doInitialSetup();
}
else if( value( "configversion" ).toUInt() != VERSION )
{
@@ -53,11 +55,15 @@ TomahawkSettings::TomahawkSettings( QObject* parent )
<< "new:" << VERSION
<< "Doing upgrade, if any...";
int current = value( "configversion" ).toUInt();
while( current < VERSION )
{
doUpgrade( current, current + 1 );
current++;
}
// insert upgrade code here as required
setValue( "configversion", VERSION );
if( contains( "script/resolvers") ) {
setValue( "script/loadedresolvers", value( "script/resolvers" ) );
}
}
}
@@ -67,6 +73,71 @@ TomahawkSettings::~TomahawkSettings()
s_instance = 0;
}
void
TomahawkSettings::doInitialSetup()
{
// by default we add a local network resolver
addSipPlugin( "sipzeroconf_autocreated" );
}
void
TomahawkSettings::doUpgrade( int oldVersion, int newVersion )
{
Q_UNUSED( newVersion );
if( oldVersion == 1 )
{
qDebug() << "Migrating config from verson 1 to 2: script resolver config name";
if( contains( "script/resolvers" ) ) {
setValue( "script/loadedresolvers", value( "script/resolvers" ) );
remove( "script/resolvers" );
}
} else if( oldVersion == 2 )
{
qDebug() << "Migrating config from version 2 to 3: Converting jabber and twitter accounts to new SIP Factory approach";
// migrate old accounts to new system. only jabber and twitter, and max one each. create a new plugin for each if needed
// not pretty as we hardcode a plugin id and assume that we know how the config layout is, but hey, this is migration after all
if( contains( "jabber/username" ) && contains( "jabber/password" ) )
{
setValue( "sipjabber_legacy/username", value( "jabber/username" ) );
setValue( "sipjabber_legacy/password", value( "jabber/password" ) );
setValue( "sipjabber_legacy/autoconnect", value( "jabber/autoconnect" ) );
setValue( "sipjabber_legacy/port", value( "jabber/port" ) );
setValue( "sipjabber_legacy/server", value( "jabber/server" ) );
addSipPlugin( "sipjabber_legacy" );
remove( "jabber/username" );
remove( "jabber/password" );
remove( "jabber/autoconnect" );
remove( "jabber/server" );
remove( "jabber/port" );
}
if( contains( "twitter/ScreenName" ) && contains( "twitter/OAuthToken" ) )
{
setValue( "siptwitter_legacy/ScreenName", value( "twitter/ScreenName" ) );
setValue( "siptwitter_legacy/OAuthToken", value( "twitter/OAuthToken" ) );
setValue( "siptwitter_legacy/OAuthTokenSecret", value( "twitter/OAuthTokenSecret" ) );
setValue( "siptwitter_legacy/CachedFriendsSinceID", value( "twitter/CachedFriendsSinceID" ) );
setValue( "siptwitter_legacy/CachedMentionsSinceID", value( "twitter/CachedMentionsSinceID" ) );
setValue( "siptwitter_legacy/CachedDirectMessagesSinceID", value( "twitter/CachedDirectMessagesSinceID" ) );
setValue( "siptwitter_legacy/CachedPeers", value( "twitter/CachedPeers" ) );
setValue( "siptwitter_legacy/AutoConnect", value( "jabber/autoconnect" ) );
addSipPlugin( "siptwitter_legacy" );
remove( "twitter/ScreenName" );
remove( "twitter/OAuthToken" );
remove( "twitter/OAuthTokenSecret" );
remove( "twitter/CachedFriendsSinceID" );
remove( "twitter/CachedMentionsSinceID" );
remove( "twitter/CachedDirectMessagesSinceID" );
}
// create a zeroconf plugin too
addSipPlugin( "sipzeroconf_legacy" );
}
}
QStringList
TomahawkSettings::scannerPaths()
@@ -326,76 +397,66 @@ TomahawkSettings::setBookmarkPlaylist( const QString& guid )
setValue( "playlists/bookmark", guid );
}
bool
TomahawkSettings::jabberAutoConnect() const
QStringList
TomahawkSettings::sipPlugins() const
{
return value( "jabber/autoconnect", true ).toBool();
return value( "sip/allplugins", QStringList() ).toStringList();
}
void
TomahawkSettings::setJabberAutoConnect( bool autoconnect )
TomahawkSettings::setSipPlugins( const QStringList& plugins )
{
setValue( "jabber/autoconnect", autoconnect );
setValue( "sip/allplugins", plugins );
}
unsigned int
TomahawkSettings::jabberPort() const
QStringList
TomahawkSettings::enabledSipPlugins() const
{
return value( "jabber/port", 5222 ).toUInt();
return value( "sip/enabledplugins", QStringList() ).toStringList();
}
void
TomahawkSettings::setJabberPort( int port )
TomahawkSettings::setEnabledSipPlugins( const QStringList& list )
{
if ( port < 0 )
return;
setValue( "jabber/port", port );
setValue( "sip/enabledplugins", list );
}
QString
TomahawkSettings::jabberServer() const
{
return value( "jabber/server" ).toString();
}
void
TomahawkSettings::setJabberServer( const QString& server )
TomahawkSettings::enableSipPlugin( const QString& pluginId )
{
setValue( "jabber/server", server );
QStringList list = enabledSipPlugins();
list << pluginId;
setEnabledSipPlugins( list );
}
QString
TomahawkSettings::jabberUsername() const
{
return value( "jabber/username" ).toString();
}
void
TomahawkSettings::setJabberUsername( const QString& username )
TomahawkSettings::disableSipPlugin( const QString& pluginId )
{
setValue( "jabber/username", username );
QStringList list = enabledSipPlugins();
list.removeAll( pluginId );
setEnabledSipPlugins( list );
}
QString
TomahawkSettings::jabberPassword() const
{
return value( "jabber/password" ).toString();
}
void
TomahawkSettings::setJabberPassword( const QString& pw )
TomahawkSettings::addSipPlugin( const QString& pluginId, bool enable )
{
setValue( "jabber/password", pw );
QStringList list = sipPlugins();
list << pluginId;
setSipPlugins( list );
if ( enable )
enableSipPlugin( pluginId );
}
void
TomahawkSettings::removeSipPlugin( const QString& pluginId )
{
QStringList list = sipPlugins();
list.removeAll( pluginId );
setSipPlugins( list );
if( enabledSipPlugins().contains( pluginId ) )
disableSipPlugin( pluginId );
}
@@ -497,90 +558,6 @@ TomahawkSettings::setLastFmUsername( const QString& username )
setValue( "lastfm/username", username );
}
QString
TomahawkSettings::twitterScreenName() const
{
return value( "twitter/ScreenName" ).toString();
}
void
TomahawkSettings::setTwitterScreenName( const QString& screenName )
{
setValue( "twitter/ScreenName", screenName );
}
QString
TomahawkSettings::twitterOAuthToken() const
{
return value( "twitter/OAuthToken" ).toString();
}
void
TomahawkSettings::setTwitterOAuthToken( const QString& oauthtoken )
{
setValue( "twitter/OAuthToken", oauthtoken );
}
QString
TomahawkSettings::twitterOAuthTokenSecret() const
{
return value( "twitter/OAuthTokenSecret" ).toString();
}
void
TomahawkSettings::setTwitterOAuthTokenSecret( const QString& oauthtokensecret )
{
setValue( "twitter/OAuthTokenSecret", oauthtokensecret );
}
qint64
TomahawkSettings::twitterCachedFriendsSinceId() const
{
return value( "twitter/CachedFriendsSinceID", 0 ).toLongLong();
}
void
TomahawkSettings::setTwitterCachedFriendsSinceId( qint64 cachedId )
{
setValue( "twitter/CachedFriendsSinceID", cachedId );
}
qint64
TomahawkSettings::twitterCachedMentionsSinceId() const
{
return value( "twitter/CachedMentionsSinceID", 0 ).toLongLong();
}
void
TomahawkSettings::setTwitterCachedMentionsSinceId( qint64 cachedId )
{
setValue( "twitter/CachedMentionsSinceID", cachedId );
}
qint64
TomahawkSettings::twitterCachedDirectMessagesSinceId() const
{
return value( "twitter/CachedDirectMessagesSinceID", 0 ).toLongLong();
}
void
TomahawkSettings::setTwitterCachedDirectMessagesSinceId( qint64 cachedId )
{
setValue( "twitter/CachedDirectMessagesSinceID", cachedId );
}
QHash<QString, QVariant>
TomahawkSettings::twitterCachedPeers() const
{
return value( "twitter/CachedPeers", QHash<QString, QVariant>() ).toHash();
}
void
TomahawkSettings::setTwitterCachedPeers( const QHash<QString, QVariant> &cachedPeers )
{
setValue( "twitter/CachedPeers", cachedPeers );
}
bool
TomahawkSettings::scrobblingEnabled() const
{

View File

@@ -69,24 +69,22 @@ public:
QStringList recentlyPlayedPlaylistGuids() const;
void appendRecentlyPlayedPlaylist( const Tomahawk::playlist_ptr& playlist );
/// SIP plugins
// all plugins we know about. loaded, unloaded, enabled, disabled.
void setSipPlugins( const QStringList& plugins );
QStringList sipPlugins() const;
void setBookmarkPlaylist( const QString& guid );
QString bookmarkPlaylist() const;
/// Jabber settings
bool jabberAutoConnect() const; /// true by default
void setJabberAutoConnect( bool autoconnect = false );
// just the enabled sip plugins.
void setEnabledSipPlugins( const QStringList& list );
QStringList enabledSipPlugins() const;
void enableSipPlugin( const QString& pluginId );
void disableSipPlugin( const QString& pluginId );
QString jabberUsername() const;
void setJabberUsername( const QString& username );
QString jabberPassword() const;
void setJabberPassword( const QString& pw );
QString jabberServer() const;
void setJabberServer( const QString& server );
unsigned int jabberPort() const; // default is 5222
void setJabberPort( int port );
void addSipPlugin( const QString& pluginId, bool enable = true );
void removeSipPlugin( const QString& pluginId );
/// Network settings
enum ExternalAddressMode { Lan, Upnp };
@@ -138,28 +136,6 @@ public:
QByteArray lastFmSessionKey() const;
void setLastFmSessionKey( const QByteArray& key );
/// Twitter settings
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 );
QHash<QString, QVariant> twitterCachedPeers() const;
void setTwitterCachedPeers( const QHash<QString, QVariant> &cachedPeers );
/// XMPP Component Settings
QString xmppBotServer() const;
void setXmppBotServer( const QString &server );
@@ -186,6 +162,9 @@ signals:
void recentlyPlayedPlaylistAdded( const Tomahawk::playlist_ptr& playlist );
private:
void doInitialSetup();
void doUpgrade( int oldVersion, int newVersion );
static TomahawkSettings* s_instance;
};

View File

@@ -27,12 +27,11 @@
#include <QMouseEvent>
#define PADDING 4
#define ICONSIZE 24
ResolverConfigDelegate::ResolverConfigDelegate( QObject* parent )
: QStyledItemDelegate( parent )
, m_configPressed( false )
: ConfigDelegateBase( parent )
{
connect( this, SIGNAL( configPressed( QModelIndex ) ), this, SLOT( onConfigPressed( QModelIndex ) ) );
}
void
@@ -61,36 +60,31 @@ ResolverConfigDelegate::paint( QPainter* painter, const QStyleOptionViewItem& op
style->drawPrimitive( QStyle::PE_PanelItemViewItem, &opt, painter, w );
int rightSplit = itemRect.width();
int rectW = opt.rect.height() - 4 * PADDING;
QRect confRect = QRect( rightSplit - rectW - 2 * PADDING, 2 * PADDING + top, rectW, rectW );
QRect confRect = QRect( rightSplit - ICONSIZE - 2 * PADDING, 2 * PADDING + top, ICONSIZE, ICONSIZE );
// if the resolver has a config widget, paint it first (right-aligned)
if( index.data( ResolversModel::HasConfig ).toBool() ) {
// draw it the same size as the check belox
QStyleOptionToolButton topt;
topt.font = opt.font;
topt.icon = QIcon( RESPATH "images/configure.png" );
topt.iconSize = QSize( 16, 16 );
topt.rect = confRect;
topt.subControls = QStyle::SC_ToolButton;
topt.activeSubControls = QStyle::SC_None;
topt.features = QStyleOptionToolButton::None;
topt.pos = confRect.topLeft();
topt.state = m_configPressed ? QStyle::State_On : QStyle::State_Raised;
if( opt.state & QStyle::State_MouseOver || m_configPressed )
topt.state |= QStyle::State_HasFocus;
style->drawComplexControl( QStyle::CC_ToolButton, &topt, painter, w );
drawConfigWrench( painter, opt, topt );
}
// draw check
confRect.moveTo( 2 * PADDING, 2 * PADDING + top );
opt.rect = confRect;
opt.checkState == Qt::Checked ? opt.state |= QStyle::State_On : opt.state |= QStyle::State_Off;
style->drawPrimitive( QStyle::PE_IndicatorViewItemCheck, &opt, painter, w );
QRect checkRect = confRect;
checkRect.moveTo( 2 * PADDING, 2 * PADDING + top );
opt.rect = checkRect;
drawCheckBox( opt, painter, w );
itemRect.setX( opt.rect.topRight().x() + PADDING );
painter->save();
painter->setFont( name );
QRect textRect = itemRect.adjusted( PADDING, PADDING, -PADDING, -PADDING );
if( index.data( ResolversModel::HasConfig ).toBool() )
textRect.setRight( confRect.topLeft().x() - PADDING );
textRect.setBottom( itemRect.height() / 2 + top );
QString nameStr = bfm.elidedText( index.data( ResolversModel::ResolverName ).toString(),Qt::ElideRight, textRect.width() );
painter->drawText( textRect, nameStr );
@@ -106,71 +100,21 @@ ResolverConfigDelegate::paint( QPainter* painter, const QStyleOptionViewItem& op
}
QSize
ResolverConfigDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const
QRect
ResolverConfigDelegate::configRectForIndex( const QStyleOptionViewItem& option, const QModelIndex& idx ) const
{
int width = QStyledItemDelegate::sizeHint( option, index ).width();
QStyleOptionViewItemV4 opt = option;
initStyleOption( &opt, index );
initStyleOption( &opt, idx );
QRect itemRect = opt.rect;
int top = itemRect.top();
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, 3 * PADDING + bfm.height() + sfm.height() );
QRect confRect = QRect( itemRect.width() - ICONSIZE - 2 * PADDING, 2 * PADDING + top, ICONSIZE, ICONSIZE );
return confRect;
}
bool
ResolverConfigDelegate::editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index)
void
ResolverConfigDelegate::onConfigPressed( const QModelIndex& idx )
{
// qDebug() << "EDITOR EVENT!" << ( event->type() == QEvent::MouseButtonRelease );
QStyleOptionViewItemV4 viewOpt( option );
initStyleOption( &viewOpt, index );
const QWidget* w = viewOpt.widget;
QStyle* style = w ? w->style() : QApplication::style();
int top = viewOpt.rect.top();
if( event->type() == QEvent::MouseButtonRelease || event->type() == QEvent::MouseButtonDblClick ) {
m_configPressed = false;
int rectW = option.rect.height() - 4 * PADDING;
QRect checkRect = QRect( 2 * PADDING, 2 * PADDING + top, rectW, rectW );
QMouseEvent* me = static_cast< QMouseEvent* >( event );
if( me->button() != Qt::LeftButton || !checkRect.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 ) {
int rightSplit = viewOpt.rect.width();
int rectW = viewOpt.rect.height() - 4 * PADDING;
QRect confRect = QRect( rightSplit - rectW - 2 * PADDING, 2 * PADDING + top, rectW, rectW );
QMouseEvent* me = static_cast< QMouseEvent* >( event );
if( me->button() == Qt::LeftButton && confRect.contains( me->pos() ) ) {
m_configPressed = true;
emit openConfig( index.data( ResolversModel::ResolverPath ).toString() );
return true;
}
}
return QStyledItemDelegate::editorEvent( event, model, option, index );
emit openConfig( idx.data( ResolversModel::ResolverPath ).toString() );
}

View File

@@ -20,23 +20,22 @@
#ifndef RESOLVERCONFIGDELEGATE_H
#define RESOLVERCONFIGDELEGATE_H
#include <QStyledItemDelegate>
#include "configdelegatebase.h"
class ResolverConfigDelegate : public QStyledItemDelegate
class ResolverConfigDelegate : public ConfigDelegateBase
{
Q_OBJECT
public:
explicit ResolverConfigDelegate(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 );
virtual QRect configRectForIndex ( const QStyleOptionViewItem& option, const QModelIndex& idx ) const;
private slots:
void onConfigPressed ( const QModelIndex& );
signals:
void openConfig( const QString& resolverPath );
private:
bool m_configPressed;
};
#endif // RESOLVERCONFIGDELEGATE_H

View File

@@ -32,7 +32,6 @@
#endif
#include "settingsdialog.h"
#include "ui_settingsdialog.h"
#include "ui_proxydialog.h"
#include "tomahawk/tomahawkapp.h"
#include "musicscanner.h"
@@ -42,7 +41,11 @@
#include "scanmanager.h"
#include "resolverconfigdelegate.h"
#include "resolversmodel.h"
#include "resolverconfigwrapper.h"
#include "delegateconfigwrapper.h"
#include "sip/SipModel.h"
#include "sipconfigdelegate.h"
#include "ui_stackedsettingsdialog.h"
static QString
md5( const QByteArray& src )
@@ -53,10 +56,12 @@ md5( const QByteArray& src )
SettingsDialog::SettingsDialog( QWidget *parent )
: QDialog( parent )
, ui( new Ui::SettingsDialog )
, ui( new Ui_StackedSettingsDialog )
, m_proxySettings( this )
, m_rejected( false )
, m_testLastFmQuery( 0 )
, m_sipModel( 0 )
, m_resolversModel( 0 )
{
ui->setupUi( this );
TomahawkSettings* s = TomahawkSettings::instance();
@@ -66,32 +71,37 @@ SettingsDialog::SettingsDialog( QWidget *parent )
ui->checkBoxUpnp->setChecked( s->externalAddressMode() == TomahawkSettings::Upnp );
ui->checkBoxUpnp->setEnabled( !s->preferStaticHostPort() );
// JABBER
ui->checkBoxJabberAutoConnect->setChecked( s->jabberAutoConnect() );
ui->jabberUsername->setText( s->jabberUsername() );
ui->jabberPassword->setText( s->jabberPassword() );
ui->jabberServer->setText( s->jabberServer() );
ui->jabberPort->setValue( s->jabberPort() );
createIcons();
#ifdef Q_WS_X11
ui->listWidget->setFrameShape( QFrame::StyledPanel );
ui->listWidget->setFrameShadow( QFrame::Sunken );
setContentsMargins( 4, 4, 4, 4 );
#else
ui->verticalLayout->removeItem( ui->verticalSpacer_3 );
#endif
// SIP PLUGINS
SipConfigDelegate* sipdel = new SipConfigDelegate( this );
ui->accountsView->setItemDelegate( sipdel );
ui->accountsView->setContextMenuPolicy( Qt::CustomContextMenu );
connect( ui->accountsView, SIGNAL( clicked( QModelIndex ) ), this, SLOT( sipItemClicked( QModelIndex ) ) );
connect( sipdel, SIGNAL( openConfig( SipPlugin* ) ), this, SLOT( openSipConfig( SipPlugin* ) ) );
connect( ui->accountsView, SIGNAL( customContextMenuRequested( QPoint ) ), this, SLOT( sipContextMenuRequest( QPoint ) ) );
m_sipModel = new SipModel( this );
ui->accountsView->setModel( m_sipModel );
setupSipButtons();
ui->staticHostName->setText( s->externalHostname() );
ui->staticPort->setValue( s->externalPort() );
ui->proxyButton->setVisible( false );
// SIP PLUGINS
foreach(SipPlugin *plugin, APP->sipHandler()->plugins())
{
if(plugin->configWidget())
{
qDebug() << "Adding configWidget for " << plugin->name();
ui->tabWidget->addTab(plugin->configWidget(), plugin->friendlyName());
}
}
// MUSIC SCANNER
//FIXME: MULTIPLECOLLECTIONDIRS
if ( s->scannerPaths().count() )
ui->lineEditMusicPath->setText( s->scannerPaths().first() );
ui->lineEditMusicPath_2->setText( s->scannerPaths().first() );
ui->checkBoxWatchForChanges->setChecked( s->watchForChanges() );
// LAST FM
@@ -112,10 +122,12 @@ SettingsDialog::SettingsDialog( QWidget *parent )
connect( ui->addScript, SIGNAL( clicked( bool ) ), this, SLOT( addScriptResolver() ) );
connect( ui->removeScript, SIGNAL( clicked( bool ) ), this, SLOT( removeScriptResolver() ) );
connect( ui->buttonBrowse, SIGNAL( clicked() ), SLOT( showPathSelector() ) );
connect( ui->buttonBrowse_2, SIGNAL( clicked() ), SLOT( showPathSelector() ) );
connect( ui->proxyButton, SIGNAL( clicked() ), SLOT( showProxySettings() ) );
connect( ui->checkBoxStaticPreferred, SIGNAL( toggled(bool) ), SLOT( toggleUpnp(bool) ) );
connect( this, SIGNAL( rejected() ), SLOT( onRejected() ) );
ui->listWidget->setCurrentRow( 0 );
}
@@ -131,16 +143,10 @@ SettingsDialog::~SettingsDialog()
s->setPreferStaticHostPort( ui->checkBoxStaticPreferred->checkState() == Qt::Checked );
s->setExternalAddressMode( ui->checkBoxUpnp->checkState() == Qt::Checked ? TomahawkSettings::Upnp : TomahawkSettings::Lan );
s->setJabberAutoConnect( ui->checkBoxJabberAutoConnect->checkState() == Qt::Checked );
s->setJabberUsername( ui->jabberUsername->text() );
s->setJabberPassword( ui->jabberPassword->text() );
s->setJabberServer( ui->jabberServer->text() );
s->setJabberPort( ui->jabberPort->value() );
s->setExternalHostname( ui->staticHostName->text() );
s->setExternalPort( ui->staticPort->value() );
s->setScannerPaths( QStringList( ui->lineEditMusicPath->text() ) );
s->setScannerPaths( QStringList( ui->lineEditMusicPath_2->text() ) );
s->setWatchForChanges( ui->checkBoxWatchForChanges->isChecked() );
s->setScrobblingEnabled( ui->checkBoxEnableLastfm->isChecked() );
@@ -158,6 +164,93 @@ SettingsDialog::~SettingsDialog()
delete ui;
}
void
SettingsDialog::createIcons()
{
/// Not fun but QListWidget sucks. Do our max-width calculation manually
/// so the icons arre lined up.
// Resolvers is the longest string... in english. fml.
int maxlen = 0;
QFontMetrics fm( font() );
QListWidgetItem *accountsButton = new QListWidgetItem( ui->listWidget );
accountsButton->setIcon( QIcon( RESPATH "images/account-settings.png" ) );
accountsButton->setText( tr( "Accounts" ) );
accountsButton->setTextAlignment( Qt::AlignHCenter );
accountsButton->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled );
maxlen = fm.width( accountsButton->text() );
QListWidgetItem *musicButton = new QListWidgetItem( ui->listWidget );
musicButton->setIcon( QIcon( RESPATH "images/music-settings.png" ) );
musicButton->setText( tr( "Music" ) );
musicButton->setTextAlignment( Qt::AlignHCenter );
musicButton->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled );
maxlen = qMax( fm.width( musicButton->text() ), maxlen );
QListWidgetItem *lastfmButton = new QListWidgetItem( ui->listWidget );
lastfmButton->setIcon( QIcon( RESPATH "images/lastfm-settings.png" ) );
lastfmButton->setText( tr( "Last.fm" ) );
lastfmButton->setTextAlignment( Qt::AlignHCenter );
lastfmButton->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled );
maxlen = qMax( fm.width( lastfmButton->text() ), maxlen );
QListWidgetItem *resolversButton = new QListWidgetItem( ui->listWidget );
resolversButton->setIcon( QIcon( RESPATH "images/resolvers-settings.png" ) );
resolversButton->setText( tr( "Resolvers" ) );
resolversButton->setTextAlignment( Qt::AlignHCenter );
resolversButton->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled );
maxlen = qMax( fm.width( resolversButton->text() ), maxlen );
QListWidgetItem *advancedButton = new QListWidgetItem( ui->listWidget );
advancedButton->setIcon( QIcon( RESPATH "images/advanced-settings.png" ) );
advancedButton->setText( tr( "Advanced" ) );
advancedButton->setTextAlignment( Qt::AlignHCenter );
advancedButton->setFlags( Qt::ItemIsSelectable | Qt::ItemIsEnabled );
maxlen = qMax( fm.width( advancedButton->text() ), maxlen );
maxlen += 15; // padding
accountsButton->setSizeHint( QSize( maxlen, 60 ) );
musicButton->setSizeHint( QSize( maxlen, 60 ) );
lastfmButton->setSizeHint( QSize( maxlen, 60 ) );
resolversButton->setSizeHint( QSize( maxlen, 60 ) );
advancedButton->setSizeHint( QSize( maxlen, 60 ) );
#ifndef Q_WS_MAC
// doesn't listen to sizehint...
ui->listWidget->setMaximumWidth( maxlen + 8 );
#endif
connect( ui->listWidget, SIGNAL( currentItemChanged( QListWidgetItem* ,QListWidgetItem* ) ), this, SLOT( changePage( QListWidgetItem*, QListWidgetItem* ) ) );
}
void
SettingsDialog::setupSipButtons()
{
foreach( SipPluginFactory* f, SipHandler::instance()->pluginFactories() ) {
if( f->isUnique() && SipHandler::instance()->hasPluginType( f->factoryId() ) ) {
continue;
}
QAction* action = new QAction( f->icon(), f->prettyName(), ui->addSipButton );
action->setProperty( "factory", QVariant::fromValue< QObject* >( f ) );
ui->addSipButton->addAction( action );
connect( action, SIGNAL( triggered(bool) ), this, SLOT( factoryActionTriggered( bool ) ) );
}
connect( ui->removeSipButton, SIGNAL( clicked( bool ) ), this, SLOT( sipPluginDeleted( bool ) ) );
}
void
SettingsDialog::changePage( QListWidgetItem* current, QListWidgetItem* previous )
{
if( !current )
current = previous;
ui->stackedWidget->setCurrentIndex( ui->listWidget->row(current) );
}
void
SettingsDialog::showPathSelector()
@@ -171,7 +264,7 @@ SettingsDialog::showPathSelector()
if ( path.isEmpty() )
return;
ui->lineEditMusicPath->setText( path );
ui->lineEditMusicPath_2->setText( path );
}
@@ -375,8 +468,8 @@ SettingsDialog::openResolverConfig( const QString& resolver )
{
Tomahawk::ExternalResolver* r = TomahawkApp::instance()->resolverForPath( resolver );
if( r && r->configUI() ) {
ResolverConfigWrapper dialog( r->configUI(), "Resolver Config", this );
QWeakPointer< ResolverConfigWrapper > watcher( &dialog );
DelegateConfigWrapper dialog( r->configUI(), "Resolver Config", this );
QWeakPointer< DelegateConfigWrapper > watcher( &dialog );
int ret = dialog.exec();
if( !watcher.isNull() && ret == QDialog::Accepted ) {
// send changed config to resolver
@@ -384,3 +477,140 @@ SettingsDialog::openResolverConfig( const QString& resolver )
}
}
}
void
SettingsDialog::sipItemClicked( const QModelIndex& item )
{
if( item.data( SipModel::FactoryRole ).toBool() )
if( ui->accountsView->isExpanded( item ) )
ui->accountsView->collapse( item );
else
ui->accountsView->expand( item );
else if( item.data( SipModel::FactoryItemRole ).toBool() )
sipFactoryClicked( qobject_cast<SipPluginFactory* >( item.data( SipModel::SipPluginFactoryData ).value< QObject* >() ) );
}
void
SettingsDialog::openSipConfig( SipPlugin* p )
{
if( p->configWidget() ) {
DelegateConfigWrapper dialog( p->configWidget(), QString("%1 Config" ).arg( p->friendlyName() ), this );
QWeakPointer< DelegateConfigWrapper > watcher( &dialog );
int ret = dialog.exec();
if( !watcher.isNull() && ret == QDialog::Accepted ) {
// send changed config to resolver
p->saveConfig();
}
}
}
void
SettingsDialog::factoryActionTriggered( bool )
{
Q_ASSERT( sender() && qobject_cast< QAction* >( sender() ) );
QAction* a = qobject_cast< QAction* >( sender() );
Q_ASSERT( qobject_cast< SipPluginFactory* >( a->property( "factory" ).value< QObject* >() ) );
SipPluginFactory* f = qobject_cast< SipPluginFactory* >( a->property( "factory" ).value< QObject* >() );
sipFactoryClicked( f );
}
void
SettingsDialog::sipFactoryClicked( SipPluginFactory* factory )
{
//if exited with OK, create it, if not, delete it immediately!
SipPlugin* p = factory->createPlugin();
bool added = false;
if( p->configWidget() ) {
DelegateConfigWrapper dialog( p->configWidget(), QString("%1 Config" ).arg( p->friendlyName() ), this );
QWeakPointer< DelegateConfigWrapper > watcher( &dialog );
int ret = dialog.exec();
if( !watcher.isNull() && ret == QDialog::Accepted ) {
// send changed config to resolver
p->saveConfig();
// accepted, so add it to tomahawk
TomahawkSettings::instance()->addSipPlugin( p->pluginId() );
SipHandler::instance()->addSipPlugin( p );
added = true;
} else {
// canceled, delete it
added = false;
}
} else {
// no config, so just add it
added = true;
TomahawkSettings::instance()->addSipPlugin( p->pluginId() );
SipHandler::instance()->addSipPlugin( p );
}
SipPluginFactory* f = SipHandler::instance()->factoryFromPlugin( p );
if( added && f && f->isUnique() ) {
// remove from actions list
QAction* toremove = 0;
foreach( QAction* a, ui->addSipButton->actions() )
{
if( f == qobject_cast< SipPluginFactory* >( a->property( "factory" ).value< QObject* >() ) )
{
toremove = a;
break;
}
}
if( toremove )
ui->addSipButton->removeAction( toremove );
} else if( added == false ) { // user pressed cancel
delete p;
}
}
void
SettingsDialog::sipContextMenuRequest( const QPoint& p )
{
QModelIndex idx = ui->accountsView->indexAt( p );
// if it's an account, allow to delete
if( idx.isValid() && !idx.data( SipModel::FactoryRole ).toBool() && !idx.data( SipModel::FactoryItemRole ).toBool() )
{
QList< QAction* > acts;
acts << new QAction( tr( "Delete Account" ), this );
acts.first()->setProperty( "sipplugin", idx.data( SipModel::SipPluginData ) );
connect( acts.first(), SIGNAL( triggered( bool ) ), this, SLOT( sipPluginRowDeleted( bool ) ) );
QMenu::exec( acts, ui->accountsView->mapToGlobal( p ) );
}
}
void
SettingsDialog::sipPluginRowDeleted( bool )
{
SipPlugin* p = qobject_cast< SipPlugin* >( qobject_cast< QAction* >( sender() )->property( "sipplugin" ).value< QObject* >() );
SipHandler::instance()->removeSipPlugin( p );
}
void
SettingsDialog::sipPluginDeleted( bool )
{
QModelIndexList indexes = ui->accountsView->selectionModel()->selectedIndexes();
// if it's an account, allow to delete
foreach( const QModelIndex& idx, indexes )
{
if( idx.isValid() && !idx.data( SipModel::FactoryRole ).toBool() && !idx.data( SipModel::FactoryItemRole ).toBool() )
{
SipPlugin* p = qobject_cast< SipPlugin* >( idx.data( SipModel::SipPluginData ).value< QObject* >() );
if( SipPluginFactory* f = SipHandler::instance()->factoryFromPlugin( p ) )
{
if( f->isUnique() ) // just deleted a unique plugin->re-add to add menu
{
QAction* action = new QAction( f->icon(), f->prettyName(), ui->addSipButton );
action->setProperty( "factory", QVariant::fromValue< QObject* >( f ) );
ui->addSipButton->addAction( action );
connect( action, SIGNAL( triggered(bool) ), this, SLOT( factoryActionTriggered( bool ) ) );
}
}
SipHandler::instance()->removeSipPlugin( p );
}
}
}

View File

@@ -20,7 +20,13 @@
#define SETTINGSDIALOG_H
#include <QDialog>
#include <QModelIndex>
class QListWidgetItem;
class Ui_StackedSettingsDialog;
class SipPluginFactory;
class SipPlugin;
class SipModel;
class ResolversModel;
class QNetworkReply;
@@ -73,13 +79,26 @@ private slots:
void scriptSelectionChanged();
void removeScriptResolver();
void openResolverConfig( const QString& );
void sipItemClicked ( const QModelIndex& );
void openSipConfig( SipPlugin* );
void factoryActionTriggered ( bool );
void sipFactoryClicked( SipPluginFactory* );
void sipContextMenuRequest( const QPoint& );
void sipPluginDeleted( bool );
void sipPluginRowDeleted( bool );
void changePage( QListWidgetItem*, QListWidgetItem* );
private:
Ui::SettingsDialog* ui;
void createIcons();
void setupSipButtons();
Ui_StackedSettingsDialog* ui;
ProxyDialog m_proxySettings;
bool m_rejected;
QNetworkReply* m_testLastFmQuery;
SipModel* m_sipModel;
ResolversModel* m_resolversModel;
};

View File

@@ -25,6 +25,35 @@
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tabFriends">
<attribute name="title">
<string>Accounts</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_20">
<item>
<widget class="QTreeView" name="accountsView">
<property name="indentation">
<number>0</number>
</property>
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<property name="uniformRowHeights">
<bool>false</bool>
</property>
<property name="animated">
<bool>true</bool>
</property>
<property name="headerHidden">
<bool>true</bool>
</property>
<property name="expandsOnDoubleClick">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabJabber">
<attribute name="title">
<string>Jabber</string>

View File

@@ -42,21 +42,21 @@ JabberPlugin::setProxy( QNetworkProxy* proxy )
const QString
JabberPlugin::name()
JabberPlugin::name() const
{
return QString( MYNAME );
}
const QString
JabberPlugin::friendlyName()
JabberPlugin::friendlyName() const
{
return QString( "Jabber" );
}
const QString
JabberPlugin::accountName()
JabberPlugin::accountName() const
{
return TomahawkSettings::instance()->jabberUsername();
}
@@ -128,6 +128,7 @@ JabberPlugin::onConnected()
emit addMenu( m_menu );
}
emit connected();
}

View File

@@ -37,10 +37,10 @@ public:
virtual ~JabberPlugin() { delete p; }
//FIXME: Make this more correct
virtual bool isValid() { return true; }
virtual const QString name();
virtual const QString friendlyName();
virtual const QString accountName();
virtual bool isValid() const { return true; }
virtual const QString name() const;
virtual const QString friendlyName() const;
virtual const QString accountName() const;
virtual QMenu* menu();
void setProxy( QNetworkProxy* proxy );

View File

@@ -20,13 +20,19 @@ set( jabberHeaders
avatarmanager.h
)
set( jabberUI
configwidget.ui
)
include_directories( . ${CMAKE_CURRENT_BINARY_DIR} ..
${QT_INCLUDE_DIR}
${LIBJREEN_INCLUDE_DIR}
)
qt4_add_resources( RC_SRCS "resources.qrc" )
qt4_wrap_ui( jabberUI_H ${jabberUI} )
qt4_wrap_cpp( jabberMoc ${jabberHeaders} )
add_library( tomahawk_sipjabber SHARED ${jabberSources} ${jabberMoc} )
add_library( tomahawk_sipjabber SHARED ${jabberSources} ${jabberMoc} ${jabberUI_H} ${RC_SRCS} )
IF( WIN32 )
SET( OS_SPECIFIC_LINK_LIBRARIES
@@ -49,3 +55,6 @@ IF( APPLE )
ENDIF( APPLE )
install( TARGETS tomahawk_sipjabber DESTINATION lib${LIB_SUFFIX} )
add_subdirectory(googlewrapper)

View File

@@ -0,0 +1,264 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>JabberConfig</class>
<widget class="QWidget" name="JabberConfig">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>437</width>
<height>207</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<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="QLabel" name="headerLabel">
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="text">
<string>Configure this Jabber account</string>
</property>
</widget>
</item>
<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>
</layout>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Login Information</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_8">
<item>
<widget class="QLabel" name="emailLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Jabber ID:</string>
</property>
<property name="buddy">
<cstring>jabberUsername</cstring>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="jabberUsername">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="placeholderText">
<string>e.g. user@example.com</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_4">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Password:</string>
</property>
<property name="buddy">
<cstring>jabberPassword</cstring>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="jabberPassword">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="inputMask">
<string/>
</property>
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="checkBoxAutoConnect">
<property name="text">
<string>Connect automatically when Tomahawk starts</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBoxJabberAdvanced">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Advanced Jabber Settings</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="labelJabberServer">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Server:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>jabberServer</cstring>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="jabberServer">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="labelJabberPort">
<property name="text">
<string>Port:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="jabberPort">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>90</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>90</width>
<height>16777215</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>65535</number>
</property>
<property name="value">
<number>5222</number>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -0,0 +1,32 @@
# fake google plugin
set( googleHeaders
../jabber.h
../tomahawksipmessage.h
../tomahawksipmessagefactory.h
../avatarmanager.h
googlewrapper.h )
set( googleSources
../jabber.cpp
../tomahawksipmessage.cpp
../tomahawksipmessagefactory.cpp
../avatarmanager.cpp
googlewrapper.cpp )
add_definitions(-DGOOGLE_WRAPPER)
qt4_add_resources( RCX_SRCS "resources.qrc" )
qt4_wrap_cpp( googleMoc ../jabber.h ../avatarmanager.h googlewrapper.h )
add_library( tomahawk_sipgoogle SHARED ${googleSources} ${googleMoc} ${googleMoc} ${RCX_SRCS} )
target_link_libraries( tomahawk_sipgoogle
${QT_LIBRARIES}
${LIBJREEN_LIBRARY}
${OS_SPECIFIC_LINK_LIBRARIES}
tomahawklib
)
install( TARGETS tomahawk_sipgoogle DESTINATION lib${LIB_SUFFIX} )

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

@@ -0,0 +1,54 @@
/*
<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 <QtPlugin>
#include "ui_configwidget.h"
SipPlugin*
GoogleWrapperFactory::createPlugin( const QString& pluginId )
{
return new GoogleWrapper( pluginId.isEmpty() ? generateId() : pluginId );
}
QIcon
GoogleWrapperFactory::icon() const
{
return QIcon( ":/gmail-logo.png" );
}
GoogleWrapper::GoogleWrapper ( const QString& pluginID )
: JabberPlugin ( pluginID )
{
m_ui->headerLabel->setText( tr( "Configure this Google Account" ) );
m_ui->emailLabel->setText( tr( "GMail Address" ) );
}
QIcon
GoogleWrapper::icon() const
{
return QIcon( ":/gmail-logo.png" );
}
#ifdef GOOGLE_WRAPPER
Q_EXPORT_PLUGIN2( sipfactory, GoogleWrapperFactory )
#endif

View File

@@ -0,0 +1,51 @@
/*
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 GOOGLEWRAPPER_H
#define GOOGLEWRAPPER_H
#include "sip/jreen/jabber.h"
class SIPDLLEXPORT GoogleWrapperFactory : public SipPluginFactory
{
Q_OBJECT
Q_INTERFACES( SipPluginFactory )
public:
GoogleWrapperFactory() {}
virtual ~GoogleWrapperFactory() {}
virtual QString prettyName() const { return "GMail"; }
virtual QString factoryId() const { return "sipgoogle"; }
virtual QIcon icon() const;
virtual SipPlugin* createPlugin( const QString& pluginId );
};
class SIPDLLEXPORT GoogleWrapper : public JabberPlugin
{
Q_OBJECT
public:
GoogleWrapper( const QString& pluginID );
virtual ~GoogleWrapper() {}
virtual const QString name() const { return QString( "GMail" ); }
virtual const QString friendlyName() const { return "GMail Friends"; }
virtual QIcon icon() const;
};
#endif // GOOGLEWRAPPER_H

View File

@@ -0,0 +1,5 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource>
<file>gmail-logo.png</file>
</qresource>
</RCC>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@@ -43,20 +43,44 @@
#include <QDateTime>
#include <QTimer>
JabberPlugin::JabberPlugin()
: m_menu( 0 )
#include "ui_configwidget.h"
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_menu( 0 )
, m_addFriendAction( 0 )
, m_connected(false)
, m_state( Disconnected )
{
qDebug() << Q_FUNC_INFO;
qsrand(QDateTime::currentDateTime().toTime_t());
// load settings
m_currentUsername = TomahawkSettings::instance()->jabberUsername();
m_currentServer = TomahawkSettings::instance()->jabberServer();
m_currentPassword = TomahawkSettings::instance()->jabberPassword();
m_currentPort = TomahawkSettings::instance()->jabberPort();
m_configWidget = QWeakPointer< QWidget >( new QWidget );
m_ui = new Ui_JabberConfig;
m_ui->setupUi( m_configWidget.data() );
m_configWidget.data()->setVisible( false );
m_ui->checkBoxAutoConnect->setChecked( readAutoConnect() );
m_ui->jabberUsername->setText( accountName() );
m_ui->jabberPassword->setText( readPassword() );
m_ui->jabberServer->setText( readServer() );
m_ui->jabberPort->setValue( readPort() );
m_currentUsername = accountName();
m_currentServer = readServer();
m_currentPassword = readPassword();
m_currentPort = readPort();
// setup JID object
Jreen::JID jid = Jreen::JID( accountName() );
@@ -135,21 +159,21 @@ JabberPlugin::setProxy( const QNetworkProxy &proxy )
const QString
JabberPlugin::name()
JabberPlugin::name() const
{
return QString( MYNAME );
}
const QString
JabberPlugin::friendlyName()
JabberPlugin::friendlyName() const
{
return QString( "Jabber" );
}
const QString
JabberPlugin::accountName()
JabberPlugin::accountName() const
{
return TomahawkSettings::instance()->jabberUsername();
return TomahawkSettings::instance()->value( pluginId() + "/username" ).toString();
}
QMenu*
@@ -158,31 +182,51 @@ JabberPlugin::menu()
return m_menu;
}
QWidget*
JabberPlugin::configWidget()
{
return m_configWidget.data();
}
QIcon
JabberPlugin::icon() const
{
return QIcon( ":/jabber-icon.png" );
}
bool
JabberPlugin::connectPlugin( bool startup )
{
qDebug() << Q_FUNC_INFO;
if ( startup && !TomahawkSettings::instance()->jabberAutoConnect() )
if ( startup && !readAutoConnect() )
return false;
qDebug() << "Connecting to the XMPP server..." << m_connected;
if(m_client->isConnected())
{
qDebug() << Q_FUNC_INFO << "Already connected to server, not connecting again...";
return true; //FIXME: should i return false here?!
}
qDebug() << "Connecting to the XMPP server...";
qDebug() << m_client->jid().full();
//m_client->setServer( m_client->jid().domain() );
qDebug() << m_client->server() << m_client->port();
//FIXME: we're badly workarounding some missing reconnection api here, to be fixed soon
QTimer::singleShot(1000, m_client, SLOT( connectToServer() ) );
//m_client->connectToServer();
m_state = Connecting;
emit stateChanged( m_state );
return true;
}
void
JabberPlugin::disconnectPlugin()
{
qDebug() << Q_FUNC_INFO << m_connected;
if(!m_connected)
if(!m_client->isConnected())
return;
foreach(const Jreen::JID &peer, m_peers.keys())
@@ -215,8 +259,6 @@ JabberPlugin::onConnect()
emit jidChanged( m_client->jid().full() );
}
emit connected();
qDebug() << "Connected as:" << m_client->jid().full();
// set presence to least valid value
@@ -240,7 +282,8 @@ 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_connected = true;
m_state = Connected;
emit stateChanged( m_state );
addMenuHelper();
}
@@ -323,14 +366,13 @@ JabberPlugin::onDisconnect( Jreen::Client::DisconnectReason reason )
Q_ASSERT(false);
break;
}
m_state = Disconnected;
emit stateChanged( m_state );
emit disconnected();
removeMenuHelper();
if(reconnect)
QTimer::singleShot(reconnectInSeconds*1000, this, SLOT(connectPlugin()));
m_connected = false;
}
void
@@ -435,25 +477,29 @@ void
JabberPlugin::checkSettings()
{
bool reconnect = false;
if ( m_currentUsername != TomahawkSettings::instance()->jabberUsername() )
if ( m_currentUsername != accountName() )
reconnect = true;
if ( m_currentPassword != TomahawkSettings::instance()->jabberPassword() )
if ( m_currentPassword != readPassword() )
reconnect = true;
if ( m_currentServer != TomahawkSettings::instance()->jabberServer() )
if ( m_currentServer != readServer() )
reconnect = true;
if ( m_currentPort != TomahawkSettings::instance()->jabberPort() )
if ( m_currentPort != readPort() )
reconnect = true;
m_currentUsername = accountName();
m_currentPassword = readPassword();
m_currentServer = readServer();
m_currentPort = readPort();
if ( reconnect )
{
qDebug() << Q_FUNC_INFO << "Reconnecting jreen plugin...";
disconnectPlugin();
m_currentUsername = TomahawkSettings::instance()->jabberUsername();
m_currentPassword = TomahawkSettings::instance()->jabberPassword();
m_currentServer = TomahawkSettings::instance()->jabberServer();
m_currentPort = TomahawkSettings::instance()->jabberPort();
m_currentUsername = accountName();
m_currentPassword = readPassword();
m_currentServer = readServer();
m_currentPort = readPort();
setupClientHelper();
@@ -844,5 +890,49 @@ void JabberPlugin::onNewAvatar(const QString& jid)
}
QString
JabberPlugin::readPassword()
{
return TomahawkSettings::instance()->value( pluginId() + "/password" ).toString();
}
Q_EXPORT_PLUGIN2( sip, JabberPlugin )
int
JabberPlugin::readPort()
{
return TomahawkSettings::instance()->value( pluginId() + "/port", 5222 ).toInt();
}
QString
JabberPlugin::readServer()
{
return TomahawkSettings::instance()->value( pluginId() + "/server" ).toString();
}
bool
JabberPlugin::readAutoConnect()
{
return TomahawkSettings::instance()->value( pluginId() + "/autoconnect", true ).toBool();
}
void
JabberPlugin::saveConfig()
{
TomahawkSettings::instance()->setValue( pluginId() + "/autoconnect", m_ui->checkBoxAutoConnect->isChecked() );
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();
}
SipPlugin::ConnectionState
JabberPlugin::connectionState() const
{
return m_state;
}
#ifndef GOOGLE_WRAPPER
Q_EXPORT_PLUGIN2( sipfactory, JabberFactory )
#endif

View File

@@ -46,21 +46,41 @@
#include "../sipdllmacro.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
{
Q_OBJECT
Q_INTERFACES( SipPlugin )
public:
JabberPlugin();
JabberPlugin( const QString& pluginId );
virtual ~JabberPlugin();
//FIXME: Make this more correct
virtual bool isValid() { return true; }
virtual const QString name();
virtual const QString friendlyName();
virtual const QString accountName();
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;
virtual QMenu* menu();
virtual QIcon icon() const;
virtual QWidget* configWidget();
virtual void saveConfig();
signals:
void jidChanged( const QString& );
@@ -74,6 +94,9 @@ public slots:
void addContact( const QString &jid, const QString& msg = QString() );
void setProxy( const QNetworkProxy &proxy );
protected:
Ui_JabberConfig* m_ui; // so the google wrapper can change the config dialog a bit
private slots:
void showAddFriendDialog();
void onConnect();
@@ -93,6 +116,11 @@ private slots:
void onNewAvatar( const QString &jid );
private:
QString readPassword();
QString readServer();
bool readAutoConnect();
int readPort();
void setupClientHelper();
void addMenuHelper();
void removeMenuHelper();
@@ -100,8 +128,6 @@ private:
bool presenceMeansOnline( Jreen::Presence::Type p );
void handlePeerStatus( const Jreen::JID &jid, Jreen::Presence::Type presenceType );
bool m_connected;
QMenu* m_menu;
QAction* m_addFriendAction;
@@ -109,6 +135,10 @@ private:
QString m_currentPassword;
QString m_currentServer;
unsigned int m_currentPort;
ConnectionState m_state;
QWeakPointer< QWidget > m_configWidget;
QString m_currentResource;
// sort out

View File

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

View File

@@ -26,9 +26,10 @@ include_directories( . ${CMAKE_CURRENT_BINARY_DIR} ..
${CMAKE_SOURCE_DIR}/thirdparty/qtweetlib/tomahawk-custom
)
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} )
add_library( tomahawk_siptwitter SHARED ${twitterUI_H} ${twitterSources} ${twitterMoc} ${RC_SRCS} )
IF( WIN32 )
SET( OS_SPECIFIC_LINK_LIBRARIES

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@@ -35,10 +35,21 @@
static QString s_gotTomahawkRegex = QString( "^(@[a-zA-Z0-9]+ )?(Got Tomahawk\\?) (\\{[a-fA-F0-9\\-]+\\}) (.*)$" );
TwitterPlugin::TwitterPlugin()
: SipPlugin()
SipPlugin*
TwitterFactory::createPlugin( const QString& pluginId )
{
return new TwitterPlugin( pluginId.isEmpty() ? generateId() : pluginId );
}
QIcon TwitterFactory::icon() const
{
return QIcon( ":/twitter-icon.png" );
}
TwitterPlugin::TwitterPlugin( const QString& pluginId )
: SipPlugin( pluginId )
, m_isAuthed( false )
, m_isOnline( false )
, m_checkTimer( this )
, m_connectTimer( this )
, m_cachedFriendsSinceId( 0 )
@@ -48,7 +59,7 @@ TwitterPlugin::TwitterPlugin()
, m_keyCache()
, m_finishedFriends( false )
, m_finishedMentions( false )
, m_configWidget( 0 )
, m_state( Disconnected )
{
qDebug() << Q_FUNC_INFO;
m_checkTimer.setInterval( 60000 );
@@ -58,51 +69,75 @@ TwitterPlugin::TwitterPlugin()
m_connectTimer.setInterval( 60000 );
m_connectTimer.setSingleShot( false );
connect( &m_connectTimer, SIGNAL( timeout() ), SLOT( connectTimerFired() ) );
m_configWidget = QWeakPointer< TwitterConfigWidget >( new TwitterConfigWidget( this, 0 ) );
connect( m_configWidget.data(), SIGNAL( twitterAuthed( bool ) ), SLOT( configDialogAuthedSignalSlot( bool ) ) );
}
void
TwitterPlugin::configDialogAuthedSignalSlot( bool authed )
{
m_isAuthed = authed;
if ( !authed )
{
TomahawkSettings::instance()->setTwitterScreenName( QString() );
TomahawkSettings::instance()->setTwitterOAuthToken( QString() );
TomahawkSettings::instance()->setTwitterOAuthTokenSecret( QString() );
if( m_isAuthed ) {
m_state = Disconnected;
emit stateChanged( m_state );
}
setTwitterScreenName( QString() );
setTwitterOAuthToken( QString() );
setTwitterOAuthTokenSecret( QString() );
}
m_isAuthed = authed;
}
bool
TwitterPlugin::isValid()
TwitterPlugin::isValid() const
{
return m_isAuthed;
}
const QString
TwitterPlugin::name()
TwitterPlugin::name() const
{
return QString( MYNAME );
}
const QString
TwitterPlugin::friendlyName()
TwitterPlugin::friendlyName() const
{
return tr("Twitter");
}
const QString
TwitterPlugin::accountName()
TwitterPlugin::accountName() const
{
return QString( TomahawkSettings::instance()->twitterScreenName() );
if( twitterScreenName().isEmpty() )
return friendlyName();
else
return twitterScreenName();
}
QIcon
TwitterPlugin::icon() const
{
return QIcon( ":/twitter-icon.png" );
}
SipPlugin::ConnectionState
TwitterPlugin::connectionState() const
{
return m_state;
}
QWidget* TwitterPlugin::configWidget()
{
m_configWidget = new TwitterConfigWidget( this );
connect( m_configWidget, SIGNAL( twitterAuthed(bool) ), SLOT( configDialogAuthedSignalSlot(bool) ) );
return m_configWidget;
return m_configWidget.data();
}
bool
@@ -110,9 +145,7 @@ TwitterPlugin::connectPlugin( bool /*startup*/ )
{
qDebug() << Q_FUNC_INFO;
TomahawkSettings *settings = TomahawkSettings::instance();
m_cachedPeers = settings->twitterCachedPeers();
m_cachedPeers = twitterCachedPeers();
QList<QString> peerlist = m_cachedPeers.keys();
qStableSort( peerlist.begin(), peerlist.end() );
foreach( QString screenName, peerlist )
@@ -123,7 +156,7 @@ TwitterPlugin::connectPlugin( bool /*startup*/ )
QMetaObject::invokeMethod( this, "registerOffer", Q_ARG( QString, screenName ), QGenericArgument( "QHash< QString, QVariant >", (const void*)&cachedPeer ) );
}
if ( settings->twitterOAuthToken().isEmpty() || settings->twitterOAuthTokenSecret().isEmpty() )
if ( twitterOAuthToken().isEmpty() || twitterOAuthTokenSecret().isEmpty() )
{
qDebug() << "TwitterPlugin has empty Twitter credentials; not connecting";
return m_cachedPeers.isEmpty();
@@ -134,6 +167,9 @@ TwitterPlugin::connectPlugin( bool /*startup*/ )
QTweetAccountVerifyCredentials *credVerifier = new QTweetAccountVerifyCredentials( m_twitterAuth.data(), this );
connect( credVerifier, SIGNAL( parsedUser(const QTweetUser &) ), SLOT( connectAuthVerifyReply(const QTweetUser &) ) );
credVerifier->verify();
m_state = Connecting;
emit stateChanged( m_state );
}
return true;
@@ -153,8 +189,6 @@ TwitterPlugin::refreshTwitterAuth()
if( m_twitterAuth.isNull() )
return false;
TomahawkSettings *settings = TomahawkSettings::instance();
m_twitterAuth.data()->setOAuthToken( settings->twitterOAuthToken().toLatin1() );
m_twitterAuth.data()->setOAuthTokenSecret( settings->twitterOAuthTokenSecret().toLatin1() );
@@ -181,7 +215,8 @@ TwitterPlugin::disconnectPlugin()
delete m_twitterAuth.data();
m_cachedPeers.empty();
m_isOnline = false;
m_state = Disconnected;
emit stateChanged( m_state );
}
void
@@ -191,6 +226,8 @@ TwitterPlugin::connectAuthVerifyReply( const QTweetUser &user )
{
qDebug() << "TwitterPlugin could not authenticate to Twitter";
m_isAuthed = false;
m_state = Disconnected;
emit stateChanged( m_state );
}
else
{
@@ -198,7 +235,7 @@ TwitterPlugin::connectAuthVerifyReply( const QTweetUser &user )
m_isAuthed = true;
if ( !m_twitterAuth.isNull() )
{
TomahawkSettings::instance()->setTwitterScreenName( user.screenName() );
setTwitterScreenName( user.screenName() );
m_friendsTimeline = QWeakPointer<QTweetFriendsTimeline>( new QTweetFriendsTimeline( m_twitterAuth.data(), this ) );
m_mentions = QWeakPointer<QTweetMentions>( new QTweetMentions( m_twitterAuth.data(), this ) );
m_directMessages = QWeakPointer<QTweetDirectMessages>( new QTweetDirectMessages( m_twitterAuth.data(), this ) );
@@ -210,7 +247,8 @@ TwitterPlugin::connectAuthVerifyReply( const QTweetUser &user )
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_isOnline = true;
m_state = Connected;
emit stateChanged( m_state );
m_connectTimer.start();
m_checkTimer.start();
QMetaObject::invokeMethod( this, "checkTimerFired", Qt::AutoConnection );
@@ -228,6 +266,8 @@ TwitterPlugin::connectAuthVerifyReply( const QTweetUser &user )
{
qDebug() << "TwitterPlugin auth pointer was null!";
m_isAuthed = false;
m_state = Disconnected;
emit stateChanged( m_state );
}
}
}
@@ -240,7 +280,7 @@ TwitterPlugin::checkTimerFired()
return;
if ( m_cachedFriendsSinceId == 0 )
m_cachedFriendsSinceId = TomahawkSettings::instance()->twitterCachedFriendsSinceId();
m_cachedFriendsSinceId = twitterCachedFriendsSinceId();
qDebug() << "TwitterPlugin looking at friends timeline since id " << m_cachedFriendsSinceId;
@@ -248,7 +288,7 @@ TwitterPlugin::checkTimerFired()
m_friendsTimeline.data()->fetch( m_cachedFriendsSinceId, 0, 800 );
if ( m_cachedMentionsSinceId == 0 )
m_cachedMentionsSinceId = TomahawkSettings::instance()->twitterCachedMentionsSinceId();
m_cachedMentionsSinceId = twitterCachedMentionsSinceId();
qDebug() << "TwitterPlugin looking at mentions timeline since id " << m_cachedMentionsSinceId;
@@ -262,7 +302,7 @@ TwitterPlugin::connectTimerFired()
if ( !isValid() || m_cachedPeers.isEmpty() || m_twitterAuth.isNull() )
return;
QString myScreenName = TomahawkSettings::instance()->twitterScreenName();
QString myScreenName = twitterScreenName();
QList<QString> peerlist = m_cachedPeers.keys();
qStableSort( peerlist.begin(), peerlist.end() );
foreach( QString screenName, peerlist )
@@ -296,7 +336,7 @@ TwitterPlugin::connectTimerFired()
void
TwitterPlugin::parseGotTomahawk( const QRegExp &regex, const QString &screenName, const QString &text )
{
QString myScreenName = TomahawkSettings::instance()->twitterScreenName();
QString myScreenName = twitterScreenName();
qDebug() << "TwitterPlugin 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 ) )
@@ -345,7 +385,7 @@ TwitterPlugin::friendsTimelineStatuses( const QList< QTweetStatus > &statuses )
{
qDebug() << Q_FUNC_INFO;
QRegExp regex( s_gotTomahawkRegex, Qt::CaseSensitive, QRegExp::RegExp2 );
QString myScreenName = TomahawkSettings::instance()->twitterScreenName();
QString myScreenName = twitterScreenName();
QHash< QString, QTweetStatus > latestHash;
foreach ( QTweetStatus status, statuses )
@@ -371,7 +411,7 @@ TwitterPlugin::friendsTimelineStatuses( const QList< QTweetStatus > &statuses )
parseGotTomahawk( regex, status.user().screenName(), status.text() );
}
TomahawkSettings::instance()->setTwitterCachedFriendsSinceId( m_cachedFriendsSinceId );
setTwitterCachedFriendsSinceId( m_cachedFriendsSinceId );
m_finishedFriends = true;
QMetaObject::invokeMethod( this, "pollDirectMessages", Qt::AutoConnection );
@@ -407,7 +447,7 @@ TwitterPlugin::mentionsStatuses( const QList< QTweetStatus > &statuses )
parseGotTomahawk( regex, status.user().screenName(), status.text() );
}
TomahawkSettings::instance()->setTwitterCachedMentionsSinceId( m_cachedMentionsSinceId );
setTwitterCachedMentionsSinceId( m_cachedMentionsSinceId );
m_finishedMentions = true;
QMetaObject::invokeMethod( this, "pollDirectMessages", Qt::AutoConnection );
@@ -426,7 +466,7 @@ TwitterPlugin::pollDirectMessages()
return;
if ( m_cachedDirectMessagesSinceId == 0 )
m_cachedDirectMessagesSinceId = TomahawkSettings::instance()->twitterCachedDirectMessagesSinceId();
m_cachedDirectMessagesSinceId = twitterCachedDirectMessagesSinceId();
qDebug() << "TwitterPlugin looking for direct messages since id " << m_cachedDirectMessagesSinceId;
@@ -440,7 +480,7 @@ TwitterPlugin::directMessages( const QList< QTweetDMStatus > &messages )
qDebug() << Q_FUNC_INFO;
QRegExp regex( s_gotTomahawkRegex, Qt::CaseSensitive, QRegExp::RegExp2 );
QString myScreenName = TomahawkSettings::instance()->twitterScreenName();
QString myScreenName = twitterScreenName();
QHash< QString, QTweetDMStatus > latestHash;
foreach ( QTweetDMStatus status, messages )
@@ -517,7 +557,7 @@ TwitterPlugin::directMessages( const QList< QTweetDMStatus > &messages )
}
}
TomahawkSettings::instance()->setTwitterCachedDirectMessagesSinceId( m_cachedDirectMessagesSinceId );
setTwitterCachedDirectMessagesSinceId( m_cachedDirectMessagesSinceId );
}
void
@@ -590,10 +630,10 @@ TwitterPlugin::registerOffer( const QString &screenName, const QHash< QString, Q
{
_peerData["lastseen"] = QString::number( QDateTime::currentMSecsSinceEpoch() );
m_cachedPeers[screenName] = QVariant::fromValue< QHash< QString, QVariant > >( _peerData );
TomahawkSettings::instance()->setTwitterCachedPeers( m_cachedPeers );
setTwitterCachedPeers( m_cachedPeers );
}
if ( m_isOnline && _peerData.contains( "host" ) && _peerData.contains( "port" ) && _peerData.contains( "pkey" ) )
if ( m_state == Connected && _peerData.contains( "host" ) && _peerData.contains( "port" ) && _peerData.contains( "pkey" ) )
QMetaObject::invokeMethod( this, "makeConnection", Q_ARG( QString, screenName ), QGenericArgument( "QHash< QString, QVariant >", (const void*)&_peerData ) );
}
@@ -662,4 +702,89 @@ TwitterPlugin::checkSettings()
connectPlugin( false );
}
Q_EXPORT_PLUGIN2( sip, TwitterPlugin )
QString
TwitterPlugin::twitterScreenName() const
{
return TomahawkSettings::instance()->value( pluginId() + "/ScreenName" ).toString();
}
void
TwitterPlugin::setTwitterScreenName( const QString& screenName )
{
TomahawkSettings::instance()->setValue( pluginId() + "/ScreenName", screenName );
}
QString
TwitterPlugin::twitterOAuthToken() const
{
return TomahawkSettings::instance()->value( pluginId() + "/OAuthToken" ).toString();
}
void
TwitterPlugin::setTwitterOAuthToken( const QString& oauthtoken )
{
TomahawkSettings::instance()->setValue( pluginId() + "/OAuthToken", oauthtoken );
}
QString
TwitterPlugin::twitterOAuthTokenSecret() const
{
return TomahawkSettings::instance()->value( pluginId() + "/OAuthTokenSecret" ).toString();
}
void
TwitterPlugin::setTwitterOAuthTokenSecret( const QString& oauthtokensecret )
{
TomahawkSettings::instance()->setValue( pluginId() + "/OAuthTokenSecret", oauthtokensecret );
}
qint64
TwitterPlugin::twitterCachedFriendsSinceId() const
{
return TomahawkSettings::instance()->value( pluginId() + "/CachedFriendsSinceID", 0 ).toLongLong();
}
void
TwitterPlugin::setTwitterCachedFriendsSinceId( qint64 cachedId )
{
TomahawkSettings::instance()->setValue( pluginId() + "/CachedFriendsSinceID", cachedId );
}
qint64
TwitterPlugin::twitterCachedMentionsSinceId() const
{
return TomahawkSettings::instance()->value( pluginId() + "/CachedMentionsSinceID", 0 ).toLongLong();
}
void
TwitterPlugin::setTwitterCachedMentionsSinceId( qint64 cachedId )
{
TomahawkSettings::instance()->setValue( pluginId() + "/CachedMentionsSinceID", cachedId );
}
qint64
TwitterPlugin::twitterCachedDirectMessagesSinceId() const
{
return TomahawkSettings::instance()->value( pluginId() + "/CachedDirectMessagesSinceID", 0 ).toLongLong();
}
void
TwitterPlugin::setTwitterCachedDirectMessagesSinceId( qint64 cachedId )
{
TomahawkSettings::instance()->setValue( pluginId() + "/CachedDirectMessagesSinceID", cachedId );
}
QHash<QString, QVariant>
TwitterPlugin::twitterCachedPeers() const
{
return TomahawkSettings::instance()->value( pluginId() + "/CachedPeers", QHash<QString, QVariant>() ).toHash();
}
void
TwitterPlugin::setTwitterCachedPeers( const QHash<QString, QVariant> &cachedPeers )
{
TomahawkSettings::instance()->setValue( pluginId() + "/CachedPeers", cachedPeers );
}
Q_EXPORT_PLUGIN2( sipfactory, TwitterFactory )

View File

@@ -40,21 +40,36 @@
#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
{
Q_OBJECT
Q_INTERFACES( SipPlugin )
public:
TwitterPlugin();
TwitterPlugin( const QString& pluginId );
virtual ~TwitterPlugin() {}
virtual bool isValid();
virtual const QString name();
virtual const QString accountName();
virtual const QString friendlyName();
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();
public slots:
@@ -98,6 +113,21 @@ private slots:
private:
bool refreshTwitterAuth();
void parseGotTomahawk( const QRegExp &regex, const QString &screenName, const QString &text );
// handle per-plugin config
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 );
QHash<QString, QVariant> twitterCachedPeers() const;
void setTwitterCachedPeers( const QHash<QString, QVariant> &cachedPeers );
QWeakPointer< TomahawkOAuthTwitter > m_twitterAuth;
QWeakPointer< QTweetFriendsTimeline > m_friendsTimeline;
@@ -105,8 +135,8 @@ private:
QWeakPointer< QTweetDirectMessages > m_directMessages;
QWeakPointer< QTweetDirectMessageNew > m_directMessageNew;
QWeakPointer< QTweetDirectMessageDestroy > m_directMessageDestroy;
bool m_isAuthed;
bool m_isOnline;
QTimer m_checkTimer;
QTimer m_connectTimer;
qint64 m_cachedFriendsSinceId;
@@ -116,8 +146,12 @@ private:
QSet<QString> m_keyCache;
bool m_finishedFriends;
bool m_finishedMentions;
ConnectionState m_state;
TwitterConfigWidget *m_configWidget;
QWeakPointer<TwitterConfigWidget > m_configWidget;
// for settings access
friend class TwitterConfigWidget;
};
#endif

View File

@@ -17,6 +17,7 @@
*/
#include "twitterconfigwidget.h"
#include "twitter.h"
#include "ui_twitterconfigwidget.h"
#include "tomahawksettings.h"
@@ -30,7 +31,7 @@
#include <QMessageBox>
TwitterConfigWidget::TwitterConfigWidget( SipPlugin* plugin, QWidget *parent ) :
TwitterConfigWidget::TwitterConfigWidget( TwitterPlugin* plugin, QWidget *parent ) :
QWidget( parent ),
ui( new Ui::TwitterConfigWidget ),
m_plugin( plugin )
@@ -48,8 +49,7 @@ TwitterConfigWidget::TwitterConfigWidget( SipPlugin* plugin, QWidget *parent ) :
ui->twitterUserTweetLineEdit->setReadOnly( true );
ui->twitterUserTweetLineEdit->setEnabled( false );
TomahawkSettings* s = TomahawkSettings::instance();
if ( s->twitterOAuthToken().isEmpty() || s->twitterOAuthTokenSecret().isEmpty() || s->twitterScreenName().isEmpty() )
if ( m_plugin->twitterOAuthToken().isEmpty() || m_plugin->twitterOAuthTokenSecret().isEmpty() || m_plugin->twitterScreenName().isEmpty() )
{
ui->twitterStatusLabel->setText( tr( "Status: No saved credentials" ) );
ui->twitterAuthenticateButton->setText( tr( "Authenticate" ) );
@@ -63,7 +63,7 @@ TwitterConfigWidget::TwitterConfigWidget( SipPlugin* plugin, QWidget *parent ) :
}
else
{
ui->twitterStatusLabel->setText( tr( "Status: Credentials saved for %1" ).arg( s->twitterScreenName() ) );
ui->twitterStatusLabel->setText( tr( "Status: Credentials saved for %1" ).arg( m_plugin->twitterScreenName() ) );
ui->twitterAuthenticateButton->setText( tr( "De-authenticate" ) );
ui->twitterInstructionsInfoLabel->setVisible( true );
ui->twitterGlobalTweetLabel->setVisible( true );
@@ -97,9 +97,8 @@ TwitterConfigWidget::authenticateTwitter()
TomahawkOAuthTwitter *twitAuth = new TomahawkOAuthTwitter( TomahawkUtils::nam(), this );
twitAuth->authorizePin();
TomahawkSettings* s = TomahawkSettings::instance();
s->setTwitterOAuthToken( twitAuth->oauthToken() );
s->setTwitterOAuthTokenSecret( twitAuth->oauthTokenSecret() );
m_plugin->setTwitterOAuthToken( twitAuth->oauthToken() );
m_plugin->setTwitterOAuthTokenSecret( twitAuth->oauthTokenSecret() );
QTweetAccountVerifyCredentials *credVerifier = new QTweetAccountVerifyCredentials( twitAuth, this );
connect( credVerifier, SIGNAL( parsedUser( const QTweetUser & ) ), SLOT( authenticateVerifyReply( const QTweetUser & ) ) );
@@ -118,12 +117,11 @@ TwitterConfigWidget::authenticateVerifyReply( const QTweetUser &user )
return;
}
TomahawkSettings* s = TomahawkSettings::instance();
s->setTwitterScreenName( user.screenName() );
s->setTwitterCachedFriendsSinceId( 0 );
s->setTwitterCachedMentionsSinceId( 0 );
m_plugin->setTwitterScreenName( user.screenName() );
m_plugin->setTwitterCachedFriendsSinceId( 0 );
m_plugin->setTwitterCachedMentionsSinceId( 0 );
ui->twitterStatusLabel->setText( tr( "Status: Credentials saved for %1" ).arg( s->twitterScreenName() ) );
ui->twitterStatusLabel->setText( tr( "Status: Credentials saved for %1" ).arg( m_plugin->twitterScreenName() ) );
ui->twitterAuthenticateButton->setText( tr( "De-authenticate" ) );
ui->twitterInstructionsInfoLabel->setVisible( true );
ui->twitterGlobalTweetLabel->setVisible( true );
@@ -150,10 +148,9 @@ void
TwitterConfigWidget::deauthenticateTwitter()
{
qDebug() << Q_FUNC_INFO;
TomahawkSettings* s = TomahawkSettings::instance();
s->setTwitterOAuthToken( QString() );
s->setTwitterOAuthTokenSecret( QString() );
s->setTwitterScreenName( QString() );
m_plugin->setTwitterOAuthToken( QString() );
m_plugin->setTwitterOAuthTokenSecret( QString() );
m_plugin->setTwitterScreenName( QString() );
ui->twitterStatusLabel->setText(tr("Status: No saved credentials"));
ui->twitterAuthenticateButton->setText( tr( "Authenticate" ) );
@@ -199,8 +196,7 @@ TwitterConfigWidget::startPostGotTomahawkStatus()
}
qDebug() << "Posting Got Tomahawk status";
TomahawkSettings* s = TomahawkSettings::instance();
if ( s->twitterOAuthToken().isEmpty() || s->twitterOAuthTokenSecret().isEmpty() || s->twitterScreenName().isEmpty() )
if ( m_plugin->twitterOAuthToken().isEmpty() || m_plugin->twitterOAuthTokenSecret().isEmpty() || m_plugin->twitterScreenName().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 );
@@ -223,11 +219,8 @@ TwitterConfigWidget::postGotTomahawkStatusAuthVerifyReply( const QTweetUser &use
emit twitterAuthed( false );
return;
}
TomahawkSettings* s = TomahawkSettings::instance();
s->setTwitterScreenName( user.screenName() );
m_plugin->setTwitterScreenName( user.screenName() );
TomahawkOAuthTwitter *twitAuth = new TomahawkOAuthTwitter( TomahawkUtils::nam(), this );
twitAuth->setOAuthToken( s->twitterOAuthToken().toLatin1() );
twitAuth->setOAuthTokenSecret( s->twitterOAuthTokenSecret().toLatin1() );
if ( m_postGTtype != "Direct Message" )
{
QTweetStatusUpdate *statUpdate = new QTweetStatusUpdate( twitAuth, this );

View File

@@ -28,6 +28,7 @@
#include <QWidget>
class TwitterPlugin;
namespace Ui {
class TwitterConfigWidget;
@@ -38,7 +39,7 @@ class TwitterConfigWidget : public QWidget
Q_OBJECT
public:
explicit TwitterConfigWidget( SipPlugin* plugin = 0, QWidget *parent = 0 );
explicit TwitterConfigWidget( TwitterPlugin* plugin = 0, QWidget *parent = 0 );
~TwitterConfigWidget();
signals:
@@ -60,7 +61,7 @@ private:
void deauthenticateTwitter();
Ui::TwitterConfigWidget *ui;
SipPlugin *m_plugin;
TwitterPlugin *m_plugin;
QString m_postGTtype;
};

View File

@@ -6,10 +6,16 @@
<rect>
<x>0</x>
<y>0</y>
<width>795</width>
<height>509</height>
<width>438</width>
<height>266</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<layout class="QVBoxLayout" name="verticalLayout_10">
<item>
<layout class="QVBoxLayout" name="twitterVertLayout">

View File

@@ -19,8 +19,9 @@ include_directories( . ${CMAKE_CURRENT_BINARY_DIR} ..
${QT_INCLUDE_DIR}
)
qt4_add_resources( RC_SRCS "resources.qrc" )
qt4_wrap_cpp( zeroconfMoc ${zeroconfHeaders} )
add_library( tomahawk_sipzeroconf SHARED ${zeroconfSources} ${zeroconfMoc} )
add_library( tomahawk_sipzeroconf SHARED ${zeroconfSources} ${zeroconfMoc} ${RC_SRCS} )
IF( WIN32 )
SET( OS_SPECIFIC_LINK_LIBRARIES

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@@ -20,24 +20,43 @@
#include <QtPlugin>
SipPlugin*
ZeroconfFactory::createPlugin( const QString& pluginId )
{
return new ZeroconfPlugin( pluginId.isEmpty() ? generateId() : pluginId );
}
const QString
ZeroconfPlugin::name()
ZeroconfPlugin::name() const
{
return QString( MYNAME );
}
const QString
ZeroconfPlugin::accountName()
ZeroconfPlugin::accountName() const
{
return QString();
return QString( MYNAME );
}
const QString
ZeroconfPlugin::friendlyName()
ZeroconfPlugin::friendlyName() const
{
return QString( "Zeroconf" );
return QString( MYNAME );
}
SipPlugin::ConnectionState
ZeroconfPlugin::connectionState() const
{
return m_state;
}
QIcon
ZeroconfFactory::icon() const
{
return QIcon( ":/zeroconf-icon.png" );
}
bool
ZeroconfPlugin::connectPlugin( bool /*startup*/ )
{
@@ -47,7 +66,7 @@ ZeroconfPlugin::connectPlugin( bool /*startup*/ )
SLOT( lanHostFound( QString, int, QString, QString ) ) );
m_zeroconf->advertise();
m_isOnline = true;
m_state = Connected;
foreach( const QStringList& nodeSet, m_cachedNodes )
{
@@ -61,12 +80,19 @@ ZeroconfPlugin::connectPlugin( bool /*startup*/ )
void
ZeroconfPlugin::disconnectPlugin()
{
m_isOnline = false;
m_state = Disconnected;
delete m_zeroconf;
m_zeroconf = 0;
}
QIcon
ZeroconfPlugin::icon() const
{
return QIcon( ":/zeroconf-icon.png" );
}
void
ZeroconfPlugin::lanHostFound( const QString& host, int port, const QString& name, const QString& nodeid )
{
@@ -75,7 +101,7 @@ ZeroconfPlugin::lanHostFound( const QString& host, int port, const QString& name
qDebug() << "Found LAN host:" << host << port << nodeid;
if ( !m_isOnline )
if ( m_state != Connected )
{
qDebug() << "Not online, so not connecting.";
QStringList nodeSet;
@@ -90,4 +116,4 @@ ZeroconfPlugin::lanHostFound( const QString& host, int port, const QString& name
qDebug() << "Already connected to" << host;
}
Q_EXPORT_PLUGIN2( sip, ZeroconfPlugin )
Q_EXPORT_PLUGIN2( sipfactory, ZeroconfFactory )

View File

@@ -24,17 +24,33 @@
#include "../sipdllmacro.h"
#define MYNAME "SIPZEROCONF"
#define MYNAME "Local Network"
class SIPDLLEXPORT ZeroconfFactory : public SipPluginFactory
{
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; }
virtual QIcon icon() const;
virtual SipPlugin* createPlugin ( const QString& pluginId = QString() );
};
class SIPDLLEXPORT ZeroconfPlugin : public SipPlugin
{
Q_OBJECT
Q_INTERFACES( SipPlugin )
public:
ZeroconfPlugin()
: m_zeroconf( 0 )
, m_isOnline( false )
ZeroconfPlugin( const QString& pluginId )
: SipPlugin( pluginId )
, m_zeroconf( 0 )
, m_state( Disconnected )
, m_cachedNodes()
{
qDebug() << Q_FUNC_INFO;
@@ -45,10 +61,12 @@ public:
qDebug() << Q_FUNC_INFO;
}
virtual bool isValid() { return true; }
virtual const QString name();
virtual const QString friendlyName();
virtual const QString accountName();
virtual const QString name() const;
virtual const QString friendlyName() const;
virtual const QString accountName() const;
virtual ConnectionState connectionState() const;
virtual bool isValid() const { return true; };
virtual QIcon icon() const;
public slots:
virtual bool connectPlugin( bool startup );
@@ -77,7 +95,7 @@ private slots:
private:
TomahawkZeroconf* m_zeroconf;
bool m_isOnline;
ConnectionState m_state;
QVector<QStringList> m_cachedNodes;
};

253
src/sipconfigdelegate.cpp Normal file
View File

@@ -0,0 +1,253 @@
/*
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 "sipconfigdelegate.h"
#include "sip/SipModel.h"
#include "sip/SipPlugin.h"
#include "utils/tomahawkutils.h"
#include <QApplication>
#include <QPainter>
#define ICONSIZE 24
SipConfigDelegate::SipConfigDelegate( QObject* parent )
: ConfigDelegateBase ( parent )
{
connect( this, SIGNAL( configPressed( QModelIndex ) ), this, SLOT( askedForEdit( QModelIndex ) ) );
}
bool
SipConfigDelegate::editorEvent ( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index )
{
return ConfigDelegateBase::editorEvent( event, model, option, index );
}
void
SipConfigDelegate::paint ( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const
{
QStyleOptionViewItemV4 opt = option;
initStyleOption( &opt, index );
QRect itemRect = opt.rect;
int top = itemRect.top();
int mid = itemRect.height() / 2;
// one line bold for account name
// space below it fro an error
// checkbox, icon, name, online/offline status, config icon
QFont name = opt.font;
name.setPointSize( name.pointSize() + 2 );
name.setBold( true );
QFont error = opt.font;
error.setItalic( true );
error.setPointSize( error.pointSize() - 2 );
// draw the background
const QWidget* w = opt.widget;
QStyle* style = w ? w->style() : QApplication::style();
style->drawPrimitive( QStyle::PE_PanelItemViewItem, &opt, painter, w );
int checkLeftEdge = 8;
int iconLeftEdge = checkLeftEdge + ICONSIZE + PADDING;
int textLeftEdge = iconLeftEdge + ICONSIZE + PADDING;
if( index.data( SipModel::FactoryRole ).toBool() ) { // this is the "add new account" row
// draw a border and background
painter->save();
painter->setRenderHints( QPainter::Antialiasing );
painter->setBrush( QApplication::palette().color( QPalette::Active, QPalette::Highlight ).lighter( 150 ) );
QPainterPath roundedRect;
roundedRect.addRoundedRect( itemRect.adjusted( 1, 1, -1, -1 ), 3, 3 );
painter->drawPath( roundedRect );
painter->setBrush( QApplication::palette().color( QPalette::Active, QPalette::Highlight ).lighter( 170 ) );
painter->fillPath( roundedRect, painter->brush() );
painter->restore();
// draw "+" icon in checkbox column
int rectW = 18;
int diff = ( ICONSIZE/ 2 ) - ( rectW / 2) ;
int pos = ( mid ) - ( rectW / 2 );
QRect plusRect = QRect( checkLeftEdge + diff, pos + top, rectW, rectW );
QPixmap p( RESPATH "images/list-add.png" );
painter->drawPixmap( plusRect, p );
// draw text
QFont f = opt.font;
f.setPointSize( f.pointSize() );
f.setBold( true );
QFontMetrics fm( f );
QString text = index.data( Qt::DisplayRole ).toString();
QRect textR = fm.boundingRect( text );
textR.moveLeft( textLeftEdge );
textR.moveTop( mid - ( textR.height() / 2 ) + top );
textR.setRight( itemRect.right() );
painter->setFont( f );
painter->drawText( textR, text );
} else if( index.data( SipModel::FactoryItemRole ).toBool() ) { // this is an account type
// ConfigDelegateBase::paint( painter, opt, index );
// int indent = 10;
// draw a border and background
painter->save();
painter->setRenderHints( QPainter::Antialiasing );
painter->setBrush( QApplication::palette().color( QPalette::Active, QPalette::Highlight ).lighter( 170 ) );
QPainterPath roundedRect;
roundedRect.addRoundedRect( itemRect.adjusted( 1, 1, -1, -1 ), 3, 3 );
painter->drawPath( roundedRect );
painter->setBrush( QApplication::palette().color( QPalette::Active, QPalette::Highlight ).lighter( 180 ) );
painter->fillPath( roundedRect, painter->brush() );
painter->restore();
QIcon icon = index.data( SipModel::FactoryItemIcon ).value< QIcon >();
if( !icon.isNull() ) {
int rectW = 18;
int diff = ( ICONSIZE/ 2 ) - ( rectW / 2) ;
int pos = ( mid ) - ( rectW / 2 );
QRect rect = QRect( checkLeftEdge + diff, pos + top, rectW, rectW );
QPixmap p( icon.pixmap( rect.size() ) );
painter->drawPixmap( rect, p );
}
// draw text
QFont f = opt.font;
f.setPointSize( f.pointSize() );
f.setBold( true );
QFontMetrics fm( f );
QString text = index.data( Qt::DisplayRole ).toString();
QRect textR = fm.boundingRect( text );
textR.moveLeft( textLeftEdge );
textR.moveTop( mid - ( textR.height() / 2 ) + top );
textR.setRight( itemRect.right() );
painter->setFont( f );
painter->drawText( textR, text );
} else { // this is an existing account to show
// draw checkbox first
int pos = ( mid ) - ( ICONSIZE / 2 );
QRect checkRect = QRect( checkLeftEdge, pos + top, ICONSIZE, ICONSIZE );
opt.rect = checkRect;
drawCheckBox( opt, painter, w );
// draw the icon if it exists
pos = ( mid ) - ( ICONSIZE / 2 );
if( !index.data( Qt::DecorationRole ).value< QIcon >().isNull() ) {
QRect prect = QRect( iconLeftEdge, pos + top, ICONSIZE, ICONSIZE );
painter->save();
painter->drawPixmap( prect, index.data( Qt::DecorationRole ).value< QIcon >().pixmap( prect.size() ) );
painter->restore();
}
// from the right edge--config status and online/offline
QRect confRect = QRect( itemRect.width() - ICONSIZE - 2 * PADDING, mid - ICONSIZE / 2 + top, ICONSIZE, ICONSIZE );
if( index.data( SipModel::HasConfig ).toBool() ) {
QStyleOptionToolButton topt;
topt.rect = confRect;
topt.pos = confRect.topLeft();
drawConfigWrench( painter, opt, topt );
}
// draw the online/offline status
int statusIconSize = 10;
int statusX = confRect.left() - 2*PADDING - statusIconSize;
QFont statusF = opt.font;
statusF.setPointSize( statusF.pointSize() - 2 );
QFontMetrics statusFM( statusF );
QPixmap p;
QString statusText;
if( index.data( SipModel::ConnectionStateRole ).toInt() == SipPlugin::Connected ) {
p = QPixmap( RESPATH "images/sipplugin-online.png" );
statusText = tr( "Online" );
} else {
p = QPixmap( RESPATH "images/sipplugin-offline.png" );
statusText = tr( "Offline" );
}
p = p.scaled( statusIconSize, statusIconSize, Qt::KeepAspectRatio, Qt::SmoothTransformation );
painter->drawPixmap( statusX, mid - statusIconSize / 2 + top, statusIconSize, statusIconSize, p );
int width = statusFM.width( statusText );
statusX = statusX - PADDING - width;
painter->save();
painter->setFont( statusF );
painter->drawText( QRect( statusX, mid - statusFM.height() / 2 + top, width, statusFM.height() ), statusText );
painter->restore();
// name
painter->save();
QFontMetrics namefm( name );
int nameHeight = namefm.boundingRect( "test" ).height();
// pos will the top-left point of the text rect
pos = mid - ( nameHeight / 2 );
// TODO bound with config icon and offline/online status
width = itemRect.width() - textLeftEdge;
if( !index.data( SipModel::ErrorString ).toString().isEmpty() ) { // error, show that too
QRect errorRect( textLeftEdge, mid + top, width, mid - PADDING );
QFontMetrics errorFm( error );
QString str = errorFm.elidedText( index.data( SipModel::ErrorString ).toString(), Qt::ElideRight, errorRect.width() );
painter->setFont( error );
painter->drawText( errorRect, str );
pos = mid - errorRect.height() - 2; // move the name rect up
}
QString nameStr = namefm.elidedText( index.data( Qt::DisplayRole ).toString(), Qt::ElideRight, width );
painter->setFont( name );
painter->drawText( QRect( textLeftEdge, pos + top, width, nameHeight ), nameStr );
painter->restore();
}
}
QRect
SipConfigDelegate::configRectForIndex( const QStyleOptionViewItem& option, const QModelIndex& idx ) const
{
QStyleOptionViewItemV4 opt = option;
initStyleOption( &opt, idx );
QRect itemRect = opt.rect;
QRect confRect = QRect( itemRect.width() - ICONSIZE - 2 * PADDING, (opt.rect.height() / 2) - ICONSIZE / 2 + opt.rect.top(), ICONSIZE, ICONSIZE );
return confRect;
}
QSize
SipConfigDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const
{
if( index.data( SipModel::FactoryRole ).toBool() || index.data( SipModel::FactoryItemRole ).toBool() ) { // this is the "add new account" row
// enough space for one line of text
QStyleOptionViewItemV4 opt = option;
initStyleOption( &opt, index );
int width = QStyledItemDelegate::sizeHint( option, index ).width();
QFont name = opt.font;
name.setPointSize( name.pointSize() + 1 );
name.setBold( true );
QFontMetrics sfm( name );
return QSize( width, 3 * PADDING + sfm.height() );
} else { // this is an existing account to show
return ConfigDelegateBase::sizeHint( option, index );
}
}
void
SipConfigDelegate::askedForEdit( const QModelIndex& idx )
{
emit openConfig( qobject_cast< SipPlugin* >( idx.data( SipModel::SipPluginData ).value< QObject* >() ) );
}

45
src/sipconfigdelegate.h Normal file
View File

@@ -0,0 +1,45 @@
/*
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 SIPCONFIGDELEGATE_H
#define SIPCONFIGDELEGATE_H
#include "configdelegatebase.h"
class SipPlugin;
class SipPluginFactory;
class SipConfigDelegate : public ConfigDelegateBase
{
Q_OBJECT
public:
SipConfigDelegate( QObject* parent = 0);
virtual void paint ( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
virtual bool editorEvent ( QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index );
virtual QSize sizeHint ( const QStyleOptionViewItem& option, const QModelIndex& index ) const;
virtual QRect configRectForIndex( const QStyleOptionViewItem& option, const QModelIndex& idx ) const;
private slots:
void askedForEdit( const QModelIndex& idx );
signals:
void sipFactoryClicked( SipPluginFactory* );
void openConfig( SipPlugin* );
};
#endif // SIPCONFIGDELEGATE_H

View File

@@ -167,7 +167,6 @@ CategoryItem::insertItems( QList< SourceTreeItem* > items )
curCount--;
beginRowsAdded( curCount, curCount + items.size() - 1 );
foreach( SourceTreeItem* item, items ) {
int index = m_showAdd ? children().count() - 1 : children().count();
insertChild( children().count() - 1, item );
}
endRowsAdded();

View File

@@ -44,7 +44,7 @@ SourcesModel::SourcesModel( QObject* parent )
appendItem( source_ptr() );
// add misc children of root node
GenericPageItem* recent = new GenericPageItem( this, m_rootItem->children().at( 0 ), tr( "Recently Played" ), QIcon( RESPATH "images/recently-played.png" ),
new GenericPageItem( this, m_rootItem->children().at( 0 ), tr( "Recently Played" ), QIcon( RESPATH "images/recently-played.png" ),
boost::bind( &ViewManager::showWelcomePage, ViewManager::instance() ),
boost::bind( &ViewManager::welcomeWidget, ViewManager::instance() )
);
@@ -193,10 +193,9 @@ SourcesModel::flags( const QModelIndex& index ) const
void
SourcesModel::appendItem( const Tomahawk::source_ptr& source )
{
beginInsertRows( QModelIndex(), rowCount(), rowCount() );
// append to end
CollectionItem* item = new CollectionItem( this, m_rootItem, source );
new CollectionItem( this, m_rootItem, source );
endInsertRows();
}
@@ -339,7 +338,7 @@ SourcesModel::linkSourceItemToPage( SourceTreeItem* item, ViewPage* p )
// TODO handle removal
m_sourceTreeLinks[ p ] = item;
if( m_viewPageDelayedCacheItem = p )
if( m_viewPageDelayedCacheItem == p )
emit selectRequest( indexFromItem( item ) );
m_viewPageDelayedCacheItem = 0;

View File

@@ -411,14 +411,12 @@ SourceDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, co
CollectionItem* colItem = qobject_cast< CollectionItem* >( item );
Q_ASSERT( colItem );
bool status = !( !colItem || colItem->source().isNull() || !colItem->source()->isOnline() );
QPixmap avatar( RESPATH "images/user-avatar.png" );
QString tracks;
QString name = index.data().toString();
int figWidth = 0;
QRect iconRect = option.rect.adjusted( 4, 6, -option.rect.width() + option.rect.height() - 12 + 4, -6 );
QPixmap avatar = index.data( Qt::DecorationRole ).value< QIcon >().pixmap( iconRect.size() );
if ( status && colItem && !colItem->source().isNull() )
{
tracks = QString::number( colItem->source()->trackCount() );
@@ -428,6 +426,7 @@ SourceDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, co
name = colItem->source()->friendlyName();
}
QRect iconRect = option.rect.adjusted( 4, 6, -option.rect.width() + option.rect.height() - 12 + 4, -6 );
painter->drawPixmap( iconRect, avatar.scaledToHeight( iconRect.height(), Qt::SmoothTransformation ) );

View File

@@ -0,0 +1,676 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>StackedSettingsDialog</class>
<widget class="QDialog" name="StackedSettingsDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>641</width>
<height>370</height>
</rect>
</property>
<property name="windowTitle">
<string>Tomahawk Settings</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_12">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>2</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QListWidget" name="listWidget">
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="autoScroll">
<bool>true</bool>
</property>
<property name="iconSize">
<size>
<width>48</width>
<height>48</height>
</size>
</property>
<property name="movement">
<enum>QListView::Static</enum>
</property>
<property name="resizeMode">
<enum>QListView::Adjust</enum>
</property>
<property name="layoutMode">
<enum>QListView::Batched</enum>
</property>
<property name="spacing">
<number>1</number>
</property>
<property name="viewMode">
<enum>QListView::IconMode</enum>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>1</width>
<height>4</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QStackedWidget" name="stackedWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="accountsPage">
<layout class="QVBoxLayout" name="verticalLayout_11">
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox_4">
<property name="title">
<string>Accounts</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_14">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Connect to your friends with Google Chat, Twitter, and more.</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QTreeView" name="accountsView">
<property name="indentation">
<number>0</number>
</property>
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<property name="uniformRowHeights">
<bool>false</bool>
</property>
<property name="animated">
<bool>true</bool>
</property>
<property name="headerHidden">
<bool>true</bool>
</property>
<property name="expandsOnDoubleClick">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="addSipLayout">
<item>
<widget class="QToolButton" name="addSipButton">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../resources.qrc">
<normaloff>:/data/images/list-add.png</normaloff>:/data/images/list-add.png</iconset>
</property>
<property name="popupMode">
<enum>QToolButton::InstantPopup</enum>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="removeSipButton">
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset resource="../resources.qrc">
<normaloff>:/data/images/list-remove.png</normaloff>:/data/images/list-remove.png</iconset>
</property>
<property name="popupMode">
<enum>QToolButton::DelayedPopup</enum>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_6">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="scannerPage">
<layout class="QVBoxLayout" name="verticalLayout_5">
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="font">
<font>
<weight>50</weight>
<bold>false</bold>
</font>
</property>
<property name="title">
<string>Local Music Information</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<property name="margin">
<number>2</number>
</property>
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>Path to scan for music files:</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLineEdit" name="lineEditMusicPath_2"/>
</item>
<item>
<widget class="QToolButton" name="buttonBrowse_2">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="checkBoxWatchForChanges">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Watch for changes</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="lastfmPage">
<layout class="QVBoxLayout" name="verticalLayout_7">
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Last.fm Login</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_6">
<property name="margin">
<number>2</number>
</property>
<item>
<widget class="QCheckBox" name="checkBoxEnableLastfm">
<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="lineEditLastfmUsername"/>
</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="lineEditLastfmPassword">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QPushButton" name="pushButtonTestLastfmLogin">
<property name="text">
<string>Test Login</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="resolversPage">
<layout class="QVBoxLayout" name="verticalLayout_10">
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Script Resolvers</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_9">
<property name="margin">
<number>2</number>
</property>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Script resolver search for a given track to make it playable.</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QTreeView" name="scriptList">
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="rootIsDecorated">
<bool>false</bool>
</property>
<property name="uniformRowHeights">
<bool>true</bool>
</property>
<property name="itemsExpandable">
<bool>false</bool>
</property>
<property name="animated">
<bool>true</bool>
</property>
<property name="headerHidden">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_8">
<item>
<widget class="QToolButton" name="addScript">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../resources.qrc">
<normaloff>:/data/images/list-add.png</normaloff>:/data/images/list-add.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="removeScript">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../resources.qrc">
<normaloff>:/data/images/list-remove.png</normaloff>:/data/images/list-remove.png</iconset>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="advancedPage">
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QGroupBox" name="groupBoxNetworkAdvanced">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Advanced Network Settings</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_13">
<property name="margin">
<number>2</number>
</property>
<item>
<layout class="QVBoxLayout" name="staticSettingsLayout">
<item>
<layout class="QHBoxLayout" name="staticPreferredLayout"/>
</item>
<item>
<widget class="QLabel" name="staticHostNamePortLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>If you're having difficulty connecting to peers, try setting this to your external IP address/host name and a port number (default 50210). Make sure to forward that port to this machine!</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="staticHostNamePortLayout">
<item>
<widget class="QLabel" name="staticHostNameLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Static Host Name:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="staticHostName"/>
</item>
<item>
<widget class="QLabel" name="staticPortLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Static Port:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="staticPort">
<property name="maximum">
<number>65535</number>
</property>
<property name="value">
<number>50210</number>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="checkBoxStaticPreferred">
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
<property name="text">
<string>Always use static host name/port? (Overrides UPnP discovery/port forwarding)</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="proxySettingsHLayout">
<item>
<spacer name="proxySettingsLeftSpacer">
<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="proxyButton">
<property name="text">
<string>Proxy Settings...</string>
</property>
</widget>
</item>
<item>
<spacer name="proxySettingsRightSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_5">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QCheckBox" name="checkBoxHttp">
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
<property name="text">
<string>Playdar HTTP API</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBoxUpnp">
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
<property name="text">
<string>Use UPnP to establish port forward</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</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>
<include location="../resources.qrc"/>
</resources>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>StackedSettingsDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>222</x>
<y>347</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>StackedSettingsDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>290</x>
<y>353</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@@ -247,7 +247,6 @@ TomahawkApp::init()
QNetworkProxy::setApplicationProxy( *TomahawkUtils::proxy() );
qDebug() << "Init SIP system.";
m_sipHandler = new SipHandler( this );
#ifndef TOMAHAWK_HEADLESS
if ( !m_headless )
@@ -323,6 +322,12 @@ TomahawkApp::audioControls()
}
#endif
SipHandler*
TomahawkApp::sipHandler()
{
return SipHandler::instance();
}
void
TomahawkApp::registerMetaTypes()
{
@@ -501,14 +506,15 @@ TomahawkApp::setupSIP()
qDebug() << Q_FUNC_INFO;
//FIXME: jabber autoconnect is really more, now that there is sip -- should be renamed and/or split out of jabber-specific settings
if( !arguments().contains( "--nosip" ) && TomahawkSettings::instance()->jabberAutoConnect() )
if( !arguments().contains( "--nosip" ) )
{
#ifdef GLOOX_FOUND
m_xmppBot = new XMPPBot( this );
#endif
qDebug() << "Connecting SIP classes";
m_sipHandler->connectPlugins( true );
SipHandler::instance()->loadFromConfig( true );
// m_sipHandler->setProxy( *TomahawkUtils::proxy() );
}

View File

@@ -179,7 +179,9 @@ TomahawkWindow::TomahawkWindow( QWidget* parent )
statusBar()->addPermanentWidget( m_audioControls, 1 );
// propagate sip menu
foreach( SipPlugin *plugin, APP->sipHandler()->plugins() )
connect( SipHandler::instance(), SIGNAL( pluginAdded( SipPlugin* ) ), this, SLOT( onSipPluginAdded( SiPlugin* ) ) );
connect( SipHandler::instance(), SIGNAL( pluginRemoved( SipPlugin* ) ), this, SLOT( onSipPluginRemoved( SiPlugin* ) ) );
foreach( SipPlugin *plugin, APP->sipHandler()->allPlugins() )
{
connect( plugin, SIGNAL( addMenu( QMenu* ) ), this, SLOT( pluginMenuAdded( QMenu* ) ) );
connect( plugin, SIGNAL( removeMenu( QMenu* ) ), this, SLOT( pluginMenuRemoved( QMenu* ) ) );
@@ -501,6 +503,19 @@ TomahawkWindow::onSipDisconnected()
ui->actionToggleConnect->setText( tr( "Go &online" ) );
}
void
TomahawkWindow::onSipPluginAdded( SipPlugin* p )
{
connect( p, SIGNAL( addMenu( QMenu* ) ), this, SLOT( pluginMenuAdded( QMenu* ) ) );
connect( p, SIGNAL( removeMenu( QMenu* ) ), this, SLOT( pluginMenuRemoved( QMenu* ) ) );
}
void
TomahawkWindow::onSipPluginRemoved( SipPlugin* p )
{
Q_UNUSED( p );
}
void
TomahawkWindow::onSipError()

View File

@@ -27,6 +27,7 @@
#include "result.h"
class SipPlugin;
class SourceTreeView;
class QAction;
@@ -83,6 +84,9 @@ private slots:
void showAboutTomahawk();
void checkForUpdates();
void onSipPluginAdded( SipPlugin* p );
void onSipPluginRemoved( SipPlugin* p );
void minimize();
void maximize();