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

You can now send global, mentions, or private (direct message) Got Tomahawk? tweets

This commit is contained in:
Jeff Mitchell
2011-03-26 15:50:28 -04:00
parent da409f9fa7
commit db53aabcf2
5 changed files with 362 additions and 100 deletions

View File

@@ -370,12 +370,57 @@ TwitterPlugin::friendsTimelineStatuses( const QList< QTweetStatus > &statuses )
QMetaObject::invokeMethod( this, "pollDirectMessages", Qt::AutoConnection );
}
void
TwitterPlugin::parseGotTomahawk( const QRegExp &regex, const QString &screenName, const QString &text )
{
QString myScreenName = TomahawkSettings::instance()->twitterScreenName();
qDebug() << "TwitterPlugin found an exact matching Got Tomahawk? mention or direct message from user " << screenName;
if ( text.startsWith( '@' ) && regex.captureCount() >= 2 && regex.cap( 1 ) != QString( '@' + myScreenName ) )
{
qDebug() << "TwitterPlugin skipping mention because it's directed @someone that isn't us";
return;
}
QString node;
for ( int i = 0; i < regex.captureCount(); ++i )
{
if ( regex.cap( i ) == QString( "Got Tomahawk?" ) )
{
QString nodeCap = regex.cap( i + 1 );
nodeCap.chop( 1 );
node = nodeCap.mid( 1 );
}
}
if ( node.isEmpty() )
{
qDebug() << "TwitterPlugin could not parse node out of the tweet";
return;
}
else
qDebug() << "TwitterPlugin parsed node " << node << " out of the tweet";
if ( screenName == myScreenName && node == Database::instance()->dbid() )
{
qDebug() << "My screen name and my dbid found; ignoring";
return;
}
QHash< QString, QVariant > peerData;
if( m_cachedPeers.contains( screenName ) )
{
peerData = m_cachedPeers[screenName].toHash();
//force a re-send of info but no need to re-register
peerData["resend"] = QVariant::fromValue< bool >( true );
}
peerData["node"] = QVariant::fromValue< QString >( node );
QMetaObject::invokeMethod( this, "registerOffer", Q_ARG( QString, screenName ), QGenericArgument( "QHash< QString, QVariant >", (const void*)&peerData ) );
}
void
TwitterPlugin::mentionsStatuses( const QList< QTweetStatus > &statuses )
{
qDebug() << Q_FUNC_INFO;
QRegExp regex( QString( "^(@[a-zA-Z0-9]+ )?(Got Tomahawk\\?) (\\{[a-fA-F0-9\\-]+\\}) (.*)$" ), Qt::CaseSensitive, QRegExp::RegExp2 );
QString myScreenName = TomahawkSettings::instance()->twitterScreenName();
QHash< QString, QTweetStatus > latestHash;
foreach ( QTweetStatus status, statuses )
@@ -393,50 +438,9 @@ TwitterPlugin::mentionsStatuses( const QList< QTweetStatus > &statuses )
{
if ( status.id() > m_cachedMentionsSinceId )
m_cachedMentionsSinceId = status.id();
if ( regex.exactMatch( status.text() ) )
{
qDebug() << "TwitterPlugin found an exact matching mention from user " << status.user().screenName();
if ( status.text().startsWith( '@' ) && regex.captureCount() >= 2 && regex.cap( 1 ) != QString( '@' + myScreenName ) )
{
qDebug() << "TwitterPlugin skipping mention because it's directed @someone that isn't us";
continue;
}
QString node;
for ( int i = 0; i < regex.captureCount(); ++i )
{
if ( regex.cap( i ) == QString( "Got Tomahawk?" ) )
{
QString nodeCap = regex.cap( i + 1 );
nodeCap.chop( 1 );
node = nodeCap.mid( 1 );
}
}
if ( node.isEmpty() )
{
qDebug() << "TwitterPlugin could not parse node out of the tweet";
continue;
}
else
qDebug() << "TwitterPlugin parsed node " << node << " out of the tweet";
if ( status.user().screenName() == myScreenName && node == Database::instance()->dbid() )
{
qDebug() << "My screen name and my dbid found; ignoring";
continue;
}
QHash< QString, QVariant > peerData;
if( m_cachedPeers.contains( status.user().screenName() ) )
{
peerData = m_cachedPeers[status.user().screenName()].toHash();
//force a re-send of info but no need to re-register
peerData["resend"] = QVariant::fromValue< bool >( true );
}
peerData["node"] = QVariant::fromValue< QString >( node );
QMetaObject::invokeMethod( this, "registerOffer", Q_ARG( QString, status.user().screenName() ), QGenericArgument( "QHash< QString, QVariant >", (const void*)&peerData ) );
}
parseGotTomahawk( regex, status.user().screenName(), status.text() );
}
TomahawkSettings::instance()->setTwitterCachedMentionsSinceId( m_cachedMentionsSinceId );
@@ -471,6 +475,9 @@ TwitterPlugin::directMessages( const QList< QTweetDMStatus > &messages )
{
qDebug() << Q_FUNC_INFO;
QRegExp regex( QString( "^(@[a-zA-Z0-9]+ )?(Got Tomahawk\\?) (\\{[a-fA-F0-9\\-]+\\}) (.*)$" ), Qt::CaseSensitive, QRegExp::RegExp2 );
QString myScreenName = TomahawkSettings::instance()->twitterScreenName();
QHash< QString, QTweetDMStatus > latestHash;
foreach ( QTweetDMStatus status, messages )
{
@@ -488,50 +495,55 @@ TwitterPlugin::directMessages( const QList< QTweetDMStatus > &messages )
qDebug() << "TwitterPlugin checking direct message from " << status.senderScreenName() << " with content " << status.text();
if ( status.id() > m_cachedDirectMessagesSinceId )
m_cachedDirectMessagesSinceId = status.id();
QStringList splitList = status.text().split(':');
qDebug() << "TwitterPlugin found " << splitList.length() << " parts to the message; the parts are:";
foreach( QString part, splitList )
qDebug() << part;
if ( splitList.length() != 5 )
continue;
if ( splitList[0] != "TOMAHAWKPEER" )
continue;
if ( !splitList[1].startsWith( "Host=" ) || !splitList[2].startsWith( "Port=" ) || !splitList[3].startsWith( "Node=" ) || !splitList[4].startsWith( "PKey=" ) )
continue;
int port = splitList[2].mid( 5 ).toInt();
if ( port == 0 )
continue;
QString host = splitList[1].mid( 5 );
QString node = splitList[3].mid( 5 );
QString pkey = splitList[4].mid( 5 );
QStringList splitNode = node.split('*');
if ( splitNode.length() != 2 )
if ( regex.exactMatch( status.text() ) )
parseGotTomahawk( regex, status.sender().screenName(), status.text() );
else
{
qDebug() << "Old-style node info found, ignoring";
continue;
}
qDebug() << "TwitterPlugin found a peerstart message from " << status.senderScreenName() << " with host " << host << " and port " << port << " and pkey " << pkey << " and node " << splitNode[0] << " destined for node " << splitNode[1];
QStringList splitList = status.text().split(':');
qDebug() << "TwitterPlugin found " << splitList.length() << " parts to the message; the parts are:";
foreach( QString part, splitList )
qDebug() << part;
if ( splitList.length() != 5 )
continue;
if ( splitList[0] != "TOMAHAWKPEER" )
continue;
if ( !splitList[1].startsWith( "Host=" ) || !splitList[2].startsWith( "Port=" ) || !splitList[3].startsWith( "Node=" ) || !splitList[4].startsWith( "PKey=" ) )
continue;
int port = splitList[2].mid( 5 ).toInt();
if ( port == 0 )
continue;
QString host = splitList[1].mid( 5 );
QString node = splitList[3].mid( 5 );
QString pkey = splitList[4].mid( 5 );
QStringList splitNode = node.split('*');
if ( splitNode.length() != 2 )
{
qDebug() << "Old-style node info found, ignoring";
continue;
}
qDebug() << "TwitterPlugin found a peerstart message from " << status.senderScreenName() << " with host " << host << " and port " << port << " and pkey " << pkey << " and node " << splitNode[0] << " destined for node " << splitNode[1];
QHash< QString, QVariant > peerData = ( m_cachedPeers.contains( status.senderScreenName() ) ) ?
m_cachedPeers[status.senderScreenName()].toHash() :
QHash< QString, QVariant >();
peerData["host"] = QVariant::fromValue< QString >( host );
peerData["port"] = QVariant::fromValue< int >( port );
peerData["pkey"] = QVariant::fromValue< QString >( pkey );
peerData["node"] = QVariant::fromValue< QString >( splitNode[0] );
peerData["dirty"] = QVariant::fromValue< bool >( true );
QHash< QString, QVariant > peerData = ( m_cachedPeers.contains( status.senderScreenName() ) ) ?
m_cachedPeers[status.senderScreenName()].toHash() :
QHash< QString, QVariant >();
peerData["host"] = QVariant::fromValue< QString >( host );
peerData["port"] = QVariant::fromValue< int >( port );
peerData["pkey"] = QVariant::fromValue< QString >( pkey );
peerData["node"] = QVariant::fromValue< QString >( splitNode[0] );
peerData["dirty"] = QVariant::fromValue< bool >( true );
QMetaObject::invokeMethod( this, "registerOffer", Q_ARG( QString, status.senderScreenName() ), QGenericArgument( "QHash< QString, QVariant >", (const void*)&peerData ) );
QMetaObject::invokeMethod( this, "registerOffer", Q_ARG( QString, status.senderScreenName() ), QGenericArgument( "QHash< QString, QVariant >", (const void*)&peerData ) );
if ( Database::instance()->dbid().startsWith( splitNode[1] ) )
{
qDebug() << "TwitterPlugin found message destined for this node; destroying it";
if ( !m_directMessageDestroy.isNull() )
m_directMessageDestroy.data()->destroyMessage( status.id() );
if ( Database::instance()->dbid().startsWith( splitNode[1] ) )
{
qDebug() << "TwitterPlugin found message destined for this node; destroying it";
if ( !m_directMessageDestroy.isNull() )
m_directMessageDestroy.data()->destroyMessage( status.id() );
}
}
}
TomahawkSettings::instance()->setTwitterCachedDirectMessagesSinceId( m_cachedDirectMessagesSinceId );

View File

@@ -92,6 +92,7 @@ private slots:
private:
bool refreshTwitterAuth();
void parseGotTomahawk( const QRegExp &regex, const QString &screenName, const QString &text );
QWeakPointer< TomahawkOAuthTwitter > m_twitterAuth;
QWeakPointer< QTweetFriendsTimeline > m_friendsTimeline;

View File

@@ -26,6 +26,7 @@
#include "tomahawkoauthtwitter.h"
#include <qtweetaccountverifycredentials.h>
#include <qtweetstatusupdate.h>
#include <qtweetdirectmessagenew.h>
#include <QMessageBox>
@@ -39,8 +40,11 @@ TwitterConfigWidget::TwitterConfigWidget(SipPlugin* plugin, QWidget *parent) :
connect(ui->twitterAuthenticateButton, SIGNAL(pressed()),
this, SLOT(authDeauthTwitter()));
connect(ui->twitterTweetGotTomahawkButton, SIGNAL(pressed()),
this, SLOT(startPostGotTomahawkStatus()));
this, SLOT(startPostGlobalGotTomahawkStatus()));
connect(ui->twitterUserTweetButton, SIGNAL(pressed()),
this, SLOT(startPostUserGotTomahawkStatus()));
connect(ui->twitterDirectTweetButton, SIGNAL(pressed()),
this, SLOT(startPostDirectGotTomahawkStatus()));
TomahawkSettings* s = TomahawkSettings::instance();
if ( s->twitterOAuthToken().isEmpty() || s->twitterOAuthTokenSecret().isEmpty() || s->twitterScreenName().isEmpty() )
@@ -48,7 +52,14 @@ TwitterConfigWidget::TwitterConfigWidget(SipPlugin* plugin, QWidget *parent) :
ui->twitterStatusLabel->setText("Status: No saved credentials");
ui->twitterAuthenticateButton->setText( "Authenticate" );
ui->twitterInstructionsInfoLabel->setVisible( false );
ui->twitterGlobalTweetLabel->setVisible( false );
ui->twitterUserTweetLabel->setVisible( false );
ui->twitterDirectTweetLabel->setVisible( false );
ui->twitterTweetGotTomahawkButton->setVisible( false );
ui->twitterUserTweetButton->setVisible( false );
ui->twitterUserTweetLineEdit->setVisible( false );
ui->twitterDirectTweetButton->setVisible( false );
ui->twitterDirectTweetLineEdit->setVisible( false );
emit twitterAuthed( false );
}
@@ -57,7 +68,14 @@ TwitterConfigWidget::TwitterConfigWidget(SipPlugin* plugin, QWidget *parent) :
ui->twitterStatusLabel->setText("Status: Credentials saved");
ui->twitterAuthenticateButton->setText( "De-authenticate" );
ui->twitterInstructionsInfoLabel->setVisible( true );
ui->twitterGlobalTweetLabel->setVisible( true );
ui->twitterUserTweetLabel->setVisible( true );
ui->twitterDirectTweetLabel->setVisible( true );
ui->twitterTweetGotTomahawkButton->setVisible( true );
ui->twitterUserTweetButton->setVisible( true );
ui->twitterUserTweetLineEdit->setVisible( true );
ui->twitterDirectTweetButton->setVisible( true );
ui->twitterDirectTweetLineEdit->setVisible( true );
emit twitterAuthed( true );
}
@@ -115,7 +133,14 @@ TwitterConfigWidget::authenticateVerifyReply( const QTweetUser &user )
ui->twitterStatusLabel->setText("Status: Credentials saved");
ui->twitterAuthenticateButton->setText( "De-authenticate" );
ui->twitterInstructionsInfoLabel->setVisible( true );
ui->twitterGlobalTweetLabel->setVisible( true );
ui->twitterUserTweetLabel->setVisible( true );
ui->twitterDirectTweetLabel->setVisible( true );
ui->twitterTweetGotTomahawkButton->setVisible( true );
ui->twitterUserTweetButton->setVisible( true );
ui->twitterUserTweetLineEdit->setVisible( true );
ui->twitterDirectTweetButton->setVisible( true );
ui->twitterDirectTweetLineEdit->setVisible( true );
m_plugin->connectPlugin( false );
@@ -132,7 +157,6 @@ TwitterConfigWidget::authenticateVerifyError( QTweetNetBase::ErrorCode code, con
return;
}
void
TwitterConfigWidget::deauthenticateTwitter()
{
@@ -145,11 +169,49 @@ TwitterConfigWidget::deauthenticateTwitter()
ui->twitterStatusLabel->setText("Status: No saved credentials");
ui->twitterAuthenticateButton->setText( "Authenticate" );
ui->twitterInstructionsInfoLabel->setVisible( false );
ui->twitterGlobalTweetLabel->setVisible( false );
ui->twitterUserTweetLabel->setVisible( false );
ui->twitterDirectTweetLabel->setVisible( false );
ui->twitterTweetGotTomahawkButton->setVisible( false );
ui->twitterUserTweetButton->setVisible( false );
ui->twitterUserTweetLineEdit->setVisible( false );
ui->twitterDirectTweetButton->setVisible( false );
ui->twitterDirectTweetLineEdit->setVisible( false );
emit twitterAuthed( false );
}
void
TwitterConfigWidget::startPostGlobalGotTomahawkStatus()
{
m_postGTtype = "global";
startPostGotTomahawkStatus();
}
void
TwitterConfigWidget::startPostUserGotTomahawkStatus()
{
if ( ui->twitterUserTweetLineEdit->text().isEmpty() || ui->twitterUserTweetLineEdit->text() == "@" )
{
QMessageBox::critical( 0, QString("Tweetin' Error"), QString("You cannot leave the user name empty when sending a mention.") );
return;
}
m_postGTtype = "user";
startPostGotTomahawkStatus();
}
void
TwitterConfigWidget::startPostDirectGotTomahawkStatus()
{
if ( ui->twitterDirectTweetLineEdit->text().isEmpty() || ui->twitterDirectTweetLineEdit->text() == "@" )
{
QMessageBox::critical( 0, QString("Tweetin' Error"), QString("You cannot leave the user name empty when sending a direct message.") );
return;
}
m_postGTtype = "direct";
startPostGotTomahawkStatus();
}
void
TwitterConfigWidget::startPostGotTomahawkStatus()
{
@@ -170,7 +232,6 @@ TwitterConfigWidget::startPostGotTomahawkStatus()
credVerifier->verify();
}
void
TwitterConfigWidget::postGotTomahawkStatusAuthVerifyReply( const QTweetUser &user )
{
@@ -186,14 +247,36 @@ TwitterConfigWidget::postGotTomahawkStatusAuthVerifyReply( const QTweetUser &use
twitAuth->setNetworkAccessManager( TomahawkUtils::nam() );
twitAuth->setOAuthToken( s->twitterOAuthToken().toLatin1() );
twitAuth->setOAuthTokenSecret( s->twitterOAuthTokenSecret().toLatin1() );
QTweetStatusUpdate *statUpdate = new QTweetStatusUpdate( twitAuth, this );
connect( statUpdate, SIGNAL( postedStatus(const QTweetStatus &) ), SLOT( postGotTomahawkStatusUpdateReply(const QTweetStatus &) ) );
connect( statUpdate, SIGNAL( error(QTweetNetBase::ErrorCode, const QString&) ), SLOT( postGotTomahawkStatusUpdateError(QTweetNetBase::ErrorCode, const QString &) ) );
QString uuid = QUuid::createUuid();
statUpdate->post( QString( "Got Tomahawk? {" ) + Database::instance()->dbid() + QString( "} (" ) + uuid.mid( 1, 8 ) + QString( ")" ) + QString( " http://gettomahawk.com" ) );
if ( m_postGTtype != "direct" )
{
QTweetStatusUpdate *statUpdate = new QTweetStatusUpdate( twitAuth, this );
connect( statUpdate, SIGNAL( postedStatus(const QTweetStatus &) ), SLOT( postGotTomahawkStatusUpdateReply(const QTweetStatus &) ) );
connect( statUpdate, SIGNAL( error(QTweetNetBase::ErrorCode, const QString&) ), SLOT( postGotTomahawkStatusUpdateError(QTweetNetBase::ErrorCode, const QString &) ) );
QString uuid = QUuid::createUuid();
QString message = QString( "Got Tomahawk? {" ) + Database::instance()->dbid() + QString( "} (" ) + uuid.mid( 1, 8 ) + QString( ")" ) + QString( " http://gettomahawk.com" );
if ( m_postGTtype == "user" )
{
QString user = ui->twitterUserTweetLineEdit->text();
if ( user.startsWith( "@" ) )
user.remove( 0, 1 );
message = QString( "@" ) + user + QString( " " ) + message;
}
statUpdate->post( message );
}
else
{
QTweetDirectMessageNew *statUpdate = new QTweetDirectMessageNew( twitAuth, this );
connect( statUpdate, SIGNAL( parsedDirectMessage(const QTweetDMStatus &)), SLOT( postGotTomahawkDirectMessageReply(const QTweetDMStatus &) ) );
connect( statUpdate, SIGNAL( error(QTweetNetBase::ErrorCode, const QString&) ), SLOT( postGotTomahawkStatusUpdateError(QTweetNetBase::ErrorCode, const QString &) ) );
QString uuid = QUuid::createUuid();
QString message = QString( "Got Tomahawk? {" ) + Database::instance()->dbid() + QString( "} (" ) + uuid.mid( 1, 8 ) + QString( ")" ) + QString( " http://gettomahawk.com" );
QString user = ui->twitterDirectTweetLineEdit->text();
if ( user.startsWith( "@" ) )
user.remove( 0, 1 );
statUpdate->post( user, message );
}
}
void
TwitterConfigWidget::postGotTomahawkStatusUpdateReply( const QTweetStatus& status )
{
@@ -203,6 +286,14 @@ TwitterConfigWidget::postGotTomahawkStatusUpdateReply( const QTweetStatus& statu
QMessageBox::information( 0, QString("Tweeted!"), QString("Your tweet has been posted!") );
}
void
TwitterConfigWidget::postGotTomahawkDirectMessageReply( const QTweetDMStatus& status )
{
if ( status.id() == 0 )
QMessageBox::critical( 0, QString("Tweetin' Error"), QString("There was an error posting your direct message -- sorry!") );
else
QMessageBox::information( 0, QString("Tweeted!"), QString("Your message has been posted!") );
}
void
TwitterConfigWidget::postGotTomahawkStatusUpdateError( QTweetNetBase::ErrorCode code, const QString& errorMsg )

View File

@@ -22,6 +22,7 @@
#include "sip/SipPlugin.h"
#include <qtweetstatus.h>
#include <qtweetdmstatus.h>
#include <qtweetuser.h>
#include <qtweetnetbase.h>
@@ -45,19 +46,24 @@ signals:
private slots:
void authDeauthTwitter();
void startPostGlobalGotTomahawkStatus();
void startPostUserGotTomahawkStatus();
void startPostDirectGotTomahawkStatus();
void startPostGotTomahawkStatus();
void authenticateVerifyReply( const QTweetUser &user );
void authenticateVerifyError( QTweetNetBase::ErrorCode code, const QString &errorMsg );
void postGotTomahawkStatusAuthVerifyReply( const QTweetUser &user );
void postGotTomahawkStatusUpdateReply( const QTweetStatus &status );
void postGotTomahawkDirectMessageReply( const QTweetDMStatus &status );
void postGotTomahawkStatusUpdateError( QTweetNetBase::ErrorCode, const QString &errorMsg );
private:
void authenticateTwitter();
void deauthenticateTwitter();
Ui::TwitterConfigWidget *ui;
SipPlugin *m_plugin;
QString m_postGTtype;
};
#endif // TWITTERCONFIGWIDGET_H

View File

@@ -65,9 +65,9 @@
<item>
<widget class="QLabel" name="twitterInstructionsInfoLabel">
<property name="text">
<string>Here's how it works: just press the button below to tweet &quot;Got Tomahawk?&quot; and some necessary information. Then be (very) patient. Twitter is an asynchronous protocol so it can take a bit!
<string>Here's how it works: just press one of the buttons below to tweet &quot;Got Tomahawk?&quot; and some necessary information. Then be (very) patient. Twitter is an asynchronous protocol so it can take a bit!
If connections to peers seem to have been lost, just press the button again to re-post a tweet for resynchronization.</string>
If connections to peers seem to have been lost, just press the appropriate button again to re-post a tweet for resynchronization.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
@@ -75,11 +75,163 @@ If connections to peers seem to have been lost, just press the button again to r
</widget>
</item>
<item>
<widget class="QPushButton" name="twitterTweetGotTomahawkButton">
<property name="text">
<string>Press here to have Tomahawk post a tweet</string>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QVBoxLayout" name="twitterTweetVLayout">
<item>
<widget class="QLabel" name="twitterGlobalTweetLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Use this button to send a normal, public tweet:</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="twitterGlobalTweetHLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2"/>
</item>
<item>
<widget class="QPushButton" name="twitterTweetGotTomahawkButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Press here to post a public tweet</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="twitterUserTweetLabel">
<property name="text">
<string>Use this button to send a public @mention to the user you enter:</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="twitterUserTweetHLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLineEdit" name="twitterUserTweetLineEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>250</width>
<height>0</height>
</size>
</property>
<property name="placeholderText">
<string>e.g. @tomahawkplayer</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="twitterUserTweetButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Press here to post a public @mention</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="twitterDirectTweetLabel">
<property name="text">
<string>Use this button to send a private, direct message to the user you enter:</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="twitterDirectTweetHLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLineEdit" name="twitterDirectTweetLineEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>250</width>
<height>0</height>
</size>
</property>
<property name="placeholderText">
<string>e.g. tomahawkplayer</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="twitterDirectTweetButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Press here to post a private message</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</item>
<item>
<spacer name="twitterVertSpacer">