mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-03-23 01:09:42 +01:00
Merge branch 'master' into watchforchanges-ng
There's some ugliness on the music page... Conflicts: src/settingsdialog.cpp src/stackedsettingsdialog.ui
This commit is contained in:
commit
6b3bb259d8
@ -5,6 +5,8 @@ SET( OS_SPECIFIC_LINK_LIBRARIES
|
||||
${COREAUDIO_LIBRARY}
|
||||
${COREFOUNDATION_LIBRARY}
|
||||
|
||||
SPMediaKeyTap
|
||||
|
||||
/System/Library/Frameworks/AppKit.framework
|
||||
/System/Library/Frameworks/Carbon.framework
|
||||
/System/Library/Frameworks/DiskArbitration.framework
|
||||
|
@ -60,6 +60,7 @@ SET( tomahawkSourcesGui ${tomahawkSourcesGui}
|
||||
sourcetree/items/genericpageitems.cpp
|
||||
|
||||
transferview.cpp
|
||||
PipelineStatusView.cpp
|
||||
tomahawktrayicon.cpp
|
||||
audiocontrols.cpp
|
||||
settingsdialog.cpp
|
||||
@ -102,6 +103,7 @@ SET( tomahawkHeadersGui ${tomahawkHeadersGui}
|
||||
sourcetree/items/genericpageitems.h
|
||||
|
||||
transferview.h
|
||||
PipelineStatusView.h
|
||||
tomahawktrayicon.h
|
||||
audiocontrols.h
|
||||
settingsdialog.h
|
||||
@ -116,10 +118,10 @@ SET( tomahawkHeadersGui ${tomahawkHeadersGui}
|
||||
|
||||
SET( tomahawkUI ${tomahawkUI}
|
||||
tomahawkwindow.ui
|
||||
settingsdialog.ui
|
||||
diagnosticsdialog.ui
|
||||
stackedsettingsdialog.ui
|
||||
proxydialog.ui
|
||||
searchbox.ui
|
||||
|
||||
audiocontrols.ui
|
||||
)
|
||||
@ -160,6 +162,8 @@ IF( UNIX )
|
||||
ENDIF( UNIX )
|
||||
|
||||
IF( APPLE )
|
||||
INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/thirdparty/SPMediaKeyTap )
|
||||
|
||||
SET( tomahawkHeaders ${tomahawkHeaders} mac/tomahawkapp_mac.h mac/macshortcuthandler.h )
|
||||
SET( tomahawkSources ${tomahawkSources} mac/tomahawkapp_mac.mm mac/macshortcuthandler.cpp )
|
||||
|
||||
|
104
src/PipelineStatusView.cpp
Normal file
104
src/PipelineStatusView.cpp
Normal file
@ -0,0 +1,104 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PipelineStatusView.h"
|
||||
|
||||
#include <QHeaderView>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "libtomahawk/pipeline.h"
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
|
||||
PipelineStatusView::PipelineStatusView( AnimatedSplitter* parent )
|
||||
: AnimatedWidget( parent )
|
||||
, m_parent( parent )
|
||||
{
|
||||
setHiddenSize( QSize( 0, 0 ) );
|
||||
setLayout( new QVBoxLayout() );
|
||||
m_tree = new QTreeWidget( this );
|
||||
|
||||
layout()->setMargin( 0 );
|
||||
layout()->addWidget( m_tree );
|
||||
|
||||
QStringList headers;
|
||||
headers << tr( "Searching For" ) << tr( "Pending" );
|
||||
m_tree->setHeaderLabels( headers );
|
||||
|
||||
m_tree->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Ignored );
|
||||
m_tree->setColumnCount( 2 );
|
||||
m_tree->setColumnWidth( 0, 200 );
|
||||
m_tree->setColumnWidth( 1, 50 );
|
||||
|
||||
m_tree->header()->setStretchLastSection( true );
|
||||
m_tree->setRootIsDecorated( false );
|
||||
|
||||
m_tree->setFrameShape( QFrame::NoFrame );
|
||||
m_tree->setAttribute( Qt::WA_MacShowFocusRect, 0 );
|
||||
|
||||
new QTreeWidgetItem( m_tree );
|
||||
|
||||
connect( Pipeline::instance(), SIGNAL( resolving( Tomahawk::query_ptr ) ), SLOT( onPipelineUpdate( Tomahawk::query_ptr ) ) );
|
||||
connect( Pipeline::instance(), SIGNAL( idle() ), SLOT( onPipelineUpdate() ) );
|
||||
|
||||
onPipelineUpdate();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
PipelineStatusView::onPipelineUpdate( const query_ptr& query )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
|
||||
QTreeWidgetItem* ti = m_tree->invisibleRootItem()->child( 0 );
|
||||
|
||||
if ( Pipeline::instance()->activeQueryCount() && !query.isNull() )
|
||||
{
|
||||
ti->setText( 0, QString( "%1 - %2" ).arg( query->artist() ).arg( query->track() ) );
|
||||
ti->setText( 1, QString( "%1" ).arg( Pipeline::instance()->activeQueryCount() + Pipeline::instance()->pendingQueryCount() ) );
|
||||
|
||||
if ( isHidden() )
|
||||
emit showWidget();
|
||||
}
|
||||
else
|
||||
{
|
||||
ti->setText( 0, tr( "Idle" ) );
|
||||
ti->setText( 1, QString( "None" ) );
|
||||
|
||||
if ( !isHidden() )
|
||||
emit hideWidget();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QSize
|
||||
PipelineStatusView::sizeHint() const
|
||||
{
|
||||
unsigned int y = 0;
|
||||
y += m_tree->header()->height();
|
||||
y += m_tree->contentsMargins().top() + m_tree->contentsMargins().bottom();
|
||||
|
||||
if ( m_tree->invisibleRootItem()->childCount() )
|
||||
{
|
||||
unsigned int rowheight = m_tree->sizeHintForRow( 0 );
|
||||
y += rowheight * m_tree->invisibleRootItem()->childCount() + 2;
|
||||
}
|
||||
|
||||
return QSize( 0, y );
|
||||
}
|
@ -16,49 +16,36 @@
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dummytranscode.h"
|
||||
#ifndef PIPELINESTATUSVIEW_H
|
||||
#define PIPELINESTATUSVIEW_H
|
||||
|
||||
#include <QDebug>
|
||||
#include <QTreeWidget>
|
||||
|
||||
DummyTranscode::DummyTranscode()
|
||||
: m_init( false )
|
||||
#include "typedefs.h"
|
||||
#include "utils/animatedsplitter.h"
|
||||
|
||||
class StreamConnection;
|
||||
|
||||
class PipelineStatusView : public AnimatedWidget
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
}
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
DummyTranscode::~DummyTranscode()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DummyTranscode::processData( const QByteArray &buffer, bool finish )
|
||||
{
|
||||
Q_UNUSED( finish );
|
||||
m_buffer.append( buffer );
|
||||
// qDebug() << "DUMMYTRANSCODING:" << buffer.size();
|
||||
|
||||
if( !m_init && m_buffer.size() >= 16364 ) {
|
||||
m_init = true;
|
||||
emit streamInitialized( 44100, 2 );
|
||||
public:
|
||||
explicit PipelineStatusView( AnimatedSplitter* parent );
|
||||
virtual ~PipelineStatusView()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
}
|
||||
}
|
||||
|
||||
QSize sizeHint() const;
|
||||
|
||||
void
|
||||
DummyTranscode::onSeek( int seconds )
|
||||
{
|
||||
Q_UNUSED( seconds );
|
||||
m_buffer.clear();
|
||||
}
|
||||
private slots:
|
||||
void onPipelineUpdate( const Tomahawk::query_ptr& query = Tomahawk::query_ptr() );
|
||||
|
||||
private:
|
||||
QTreeWidget* m_tree;
|
||||
AnimatedSplitter* m_parent;
|
||||
};
|
||||
|
||||
void
|
||||
DummyTranscode::clearBuffers()
|
||||
{
|
||||
m_buffer.clear();
|
||||
m_init = false;
|
||||
}
|
||||
|
||||
#endif // TRANSFERVIEW_H
|
@ -80,27 +80,23 @@ AudioControls::AudioControls( QWidget* parent )
|
||||
ui->metaDataArea->setStyleSheet( "QWidget#metaDataArea {\nborder-width: 4px;\nborder-image: url(" RESPATH "images/now-playing-panel.png) 4 4 4 4 stretch stretch; }" );
|
||||
|
||||
ui->seekSlider->setFixedHeight( 20 );
|
||||
ui->seekSlider->setEnabled( false );
|
||||
ui->seekSlider->setEnabled( true );
|
||||
ui->seekSlider->setStyleSheet( "QSlider::groove::horizontal {"
|
||||
"margin: 5px; border-width: 3px;"
|
||||
"border-image: url(" RESPATH "images/seek-slider-bkg.png) 3 3 3 3 stretch stretch;"
|
||||
"}"
|
||||
|
||||
"QSlider::handle::horizontal {"
|
||||
"margin-left: 5px; margin-right: -5px; "
|
||||
"width: 0px;"
|
||||
|
||||
//"margin-bottom: -7px; margin-top: -7px;"
|
||||
//"height: 17px; width: 16px;"
|
||||
//"background-image: url(" RESPATH "images/seek-and-volume-knob-rest.png);"
|
||||
//"background-repeat: no-repeat;"
|
||||
"}"
|
||||
|
||||
"QSlider::sub-page:horizontal {"
|
||||
"margin: 5px; border-width: 3px;"
|
||||
"border-image: url(" RESPATH "images/seek-slider-level.png) 3 3 3 3 stretch stretch;"
|
||||
"}"
|
||||
);
|
||||
|
||||
"QSlider::handle::horizontal {"
|
||||
"margin-bottom: -7px; margin-top: -7px;"
|
||||
"height: 17px; width: 16px;"
|
||||
"background-image: url(" RESPATH "images/seek-and-volume-knob-rest.png);"
|
||||
"background-repeat: no-repeat;"
|
||||
"}" );
|
||||
|
||||
ui->volumeSlider->setFixedHeight( 20 );
|
||||
ui->volumeSlider->setRange( 0, 100 );
|
||||
@ -120,9 +116,7 @@ AudioControls::AudioControls( QWidget* parent )
|
||||
"height: 17px; width: 16px;"
|
||||
"background-image: url(" RESPATH "images/seek-and-volume-knob-rest.png);"
|
||||
"background-repeat: no-repeat;"
|
||||
"}"
|
||||
|
||||
);
|
||||
"}" );
|
||||
|
||||
/* m_playAction = new QAction( this );
|
||||
m_pauseAction = new QAction( this );
|
||||
@ -134,6 +128,7 @@ AudioControls::AudioControls( QWidget* parent )
|
||||
connect( m_prevAction, SIGNAL( triggered() ), (QObject*)APP->audioEngine(), SLOT( previous() ) );
|
||||
connect( m_nextAction, SIGNAL( triggered() ), (QObject*)APP->audioEngine(), SLOT( next() ) ); */
|
||||
|
||||
connect( ui->seekSlider, SIGNAL( valueChanged( int ) ), AudioEngine::instance(), SLOT( seek( int ) ) );
|
||||
connect( ui->volumeSlider, SIGNAL( valueChanged( int ) ), AudioEngine::instance(), SLOT( setVolume( int ) ) );
|
||||
connect( ui->prevButton, SIGNAL( clicked() ), AudioEngine::instance(), SLOT( previous() ) );
|
||||
connect( ui->playPauseButton, SIGNAL( clicked() ), AudioEngine::instance(), SLOT( play() ) );
|
||||
@ -283,13 +278,11 @@ AudioControls::onPlaybackLoading( const Tomahawk::result_ptr& result )
|
||||
ui->ownerLabel->setText( result->friendlySource() );
|
||||
ui->coverImage->setPixmap( m_defaultCover );
|
||||
|
||||
if ( ui->timeLabel->text().isEmpty() )
|
||||
ui->timeLabel->setText( TomahawkUtils::timeToString( 0 ) );
|
||||
|
||||
if ( ui->timeLeftLabel->text().isEmpty() )
|
||||
ui->timeLeftLabel->setText( "-" + TomahawkUtils::timeToString( result->duration() ) );
|
||||
ui->timeLabel->setText( TomahawkUtils::timeToString( 0 ) );
|
||||
ui->timeLeftLabel->setText( "-" + TomahawkUtils::timeToString( result->duration() ) );
|
||||
|
||||
ui->seekSlider->setRange( 0, m_currentTrack->duration() * 1000 );
|
||||
ui->seekSlider->setValue( 0 );
|
||||
ui->seekSlider->setVisible( true );
|
||||
|
||||
/* m_playAction->setEnabled( false );
|
||||
@ -357,10 +350,14 @@ AudioControls::onPlaybackTimer( qint64 msElapsed )
|
||||
if ( m_currentTrack.isNull() )
|
||||
return;
|
||||
|
||||
ui->seekSlider->blockSignals( true );
|
||||
|
||||
const int seconds = msElapsed / 1000;
|
||||
ui->timeLabel->setText( TomahawkUtils::timeToString( seconds ) );
|
||||
ui->timeLeftLabel->setText( "-" + TomahawkUtils::timeToString( m_currentTrack->duration() - seconds ) );
|
||||
ui->seekSlider->setValue( msElapsed );
|
||||
|
||||
ui->seekSlider->blockSignals( false );
|
||||
}
|
||||
|
||||
|
||||
|
@ -28,8 +28,10 @@ class DelegateConfigWrapper : public QDialog
|
||||
public:
|
||||
DelegateConfigWrapper( QWidget* conf, const QString& title, QWidget* parent, Qt::WindowFlags flags = 0 ) : QDialog( parent, flags ), m_widget( conf )
|
||||
{
|
||||
m_widget->setVisible( true );
|
||||
m_widget->setWindowFlags( Qt::Sheet );
|
||||
#ifdef Q_OS_MAC
|
||||
m_widget->setVisible( true );
|
||||
#endif
|
||||
|
||||
setWindowTitle( title );
|
||||
QVBoxLayout* v = new QVBoxLayout( this );
|
||||
@ -47,7 +49,12 @@ public:
|
||||
setSizeGripEnabled( false );
|
||||
setMinimumSize( sizeHint() );
|
||||
setMaximumSize( sizeHint() ); // to remove the resize grip on osx this is the only way
|
||||
|
||||
connect( conf, SIGNAL( sizeHintChanged() ), this, SLOT( updateSizeHint() ) );
|
||||
#else
|
||||
m_widget->setVisible( true );
|
||||
#endif
|
||||
|
||||
}
|
||||
public slots:
|
||||
void closed( QAbstractButton* b )
|
||||
@ -72,6 +79,15 @@ public slots:
|
||||
m_widget->setVisible( false );
|
||||
}
|
||||
|
||||
void updateSizeHint() {
|
||||
hide();
|
||||
setSizeGripEnabled( false );
|
||||
setMinimumSize( sizeHint() );
|
||||
setMaximumSize( sizeHint() );
|
||||
|
||||
show();
|
||||
}
|
||||
|
||||
private:
|
||||
QWidget* m_widget;
|
||||
};
|
||||
|
@ -162,6 +162,7 @@ set( libSources
|
||||
utils/xspfgenerator.cpp
|
||||
|
||||
widgets/newplaylistwidget.cpp
|
||||
widgets/searchwidget.cpp
|
||||
widgets/playlisttypeselectordlg.cpp
|
||||
widgets/welcomewidget.cpp
|
||||
widgets/welcomeplaylistmodel.cpp
|
||||
@ -327,6 +328,7 @@ set( libHeaders
|
||||
utils/xspfgenerator.h
|
||||
|
||||
widgets/newplaylistwidget.h
|
||||
widgets/searchwidget.h
|
||||
widgets/playlisttypeselectordlg.h
|
||||
widgets/welcomewidget.h
|
||||
widgets/welcomeplaylistmodel.h
|
||||
@ -345,6 +347,7 @@ set( libHeaders_NoMOC
|
||||
set( libUI ${libUI}
|
||||
widgets/playlisttypeselectordlg.ui
|
||||
widgets/newplaylistwidget.ui
|
||||
widgets/searchwidget.ui
|
||||
widgets/welcomewidget.ui
|
||||
widgets/infowidgets/sourceinfowidget.ui
|
||||
playlist/topbar/topbar.ui
|
||||
@ -386,13 +389,25 @@ ENDIF( WIN32 )
|
||||
IF( APPLE )
|
||||
FIND_LIBRARY( COREAUDIO_LIBRARY CoreAudio )
|
||||
FIND_LIBRARY( COREFOUNDATION_LIBRARY CoreFoundation )
|
||||
MARK_AS_ADVANCED( COREAUDIO_LIBRARY COREFOUNDATION_LIBRARY )
|
||||
FIND_LIBRARY( FOUNDATION_LIBRARY Foundation )
|
||||
FIND_LIBRARY( SCRIPTINGBRIDGE_LIBRARY ScriptingBridge )
|
||||
MARK_AS_ADVANCED( COREAUDIO_LIBRARY COREFOUNDATION_LIBRARY FOUNDATION_LIBRARY SCRIPTINGBRIDGE_LIBRARY )
|
||||
|
||||
SET( libSources ${libSources}
|
||||
infosystem/infoplugins/adium.mm
|
||||
infosystem/infoplugins/adiumplugin.cpp )
|
||||
|
||||
SET( libHeaders ${libHeaders}
|
||||
infosystem/infoplugins/adium.h
|
||||
infosystem/infoplugins/adiumplugin.h )
|
||||
|
||||
SET( OS_SPECIFIC_LINK_LIBRARIES
|
||||
${OS_SPECIFIC_LINK_LIBRARIES}
|
||||
# System
|
||||
${COREAUDIO_LIBRARY}
|
||||
${COREFOUNDATION_LIBRARY}
|
||||
${FOUNDATION_LIBRARY}
|
||||
${SCRIPTINGBRIDGE_LIBRARY}
|
||||
)
|
||||
ENDIF( APPLE )
|
||||
|
||||
|
@ -24,10 +24,14 @@
|
||||
|
||||
#include "database/database.h"
|
||||
#include "database/databasecommand_logplayback.h"
|
||||
#include "infosystem/infosystem.h"
|
||||
#include "network/servent.h"
|
||||
|
||||
#include "album.h"
|
||||
|
||||
AudioEngine* AudioEngine::s_instance = 0;
|
||||
|
||||
static QString s_aeInfoIdentifier = QString( "AUDIOENGINE" );
|
||||
|
||||
AudioEngine*
|
||||
AudioEngine::instance()
|
||||
@ -57,6 +61,11 @@ AudioEngine::AudioEngine()
|
||||
m_mediaObject->setTickInterval( 150 );
|
||||
connect( m_mediaObject, SIGNAL( stateChanged( Phonon::State, Phonon::State ) ), SLOT( onStateChanged( Phonon::State, Phonon::State ) ) );
|
||||
connect( m_mediaObject, SIGNAL( tick( qint64 ) ), SLOT( timerTriggered( qint64 ) ) );
|
||||
connect( m_mediaObject, SIGNAL( aboutToFinish() ), SLOT( onAboutToFinish() ) );
|
||||
|
||||
connect( m_audioOutput, SIGNAL( volumeChanged( qreal ) ), this, SLOT( onVolumeChanged( qreal ) ) );
|
||||
|
||||
onVolumeChanged( m_audioOutput->volume() );
|
||||
}
|
||||
|
||||
|
||||
@ -91,6 +100,14 @@ AudioEngine::play()
|
||||
{
|
||||
m_mediaObject->play();
|
||||
emit resumed();
|
||||
Tomahawk::InfoSystem::InfoCriteriaHash trackInfo;
|
||||
|
||||
trackInfo["title"] = m_currentTrack->track();
|
||||
trackInfo["artist"] = m_currentTrack->artist()->name();
|
||||
trackInfo["album"] = m_currentTrack->album()->name();
|
||||
Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo(
|
||||
s_aeInfoIdentifier, Tomahawk::InfoSystem::InfoNowResumed,
|
||||
QVariant::fromValue< Tomahawk::InfoSystem::InfoCriteriaHash >( trackInfo ) );
|
||||
}
|
||||
else
|
||||
loadNextTrack();
|
||||
@ -104,6 +121,8 @@ AudioEngine::pause()
|
||||
|
||||
m_mediaObject->pause();
|
||||
emit paused();
|
||||
Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo(
|
||||
s_aeInfoIdentifier, Tomahawk::InfoSystem::InfoNowPaused, QVariant() );
|
||||
}
|
||||
|
||||
|
||||
@ -112,11 +131,12 @@ AudioEngine::stop()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
|
||||
m_expectStop = true;
|
||||
m_mediaObject->stop();
|
||||
|
||||
setCurrentTrack( Tomahawk::result_ptr() );
|
||||
emit stopped();
|
||||
Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo(
|
||||
s_aeInfoIdentifier, Tomahawk::InfoSystem::InfoNowStopped, QVariant() );
|
||||
}
|
||||
|
||||
|
||||
@ -136,6 +156,17 @@ AudioEngine::next()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AudioEngine::seek( int ms )
|
||||
{
|
||||
if ( isPlaying() || isPaused() )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << ms;
|
||||
m_mediaObject->seek( ms );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AudioEngine::setVolume( int percentage )
|
||||
{
|
||||
@ -146,7 +177,6 @@ AudioEngine::setVolume( int percentage )
|
||||
emit volumeChanged( percentage );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AudioEngine::mute()
|
||||
{
|
||||
@ -176,7 +206,7 @@ AudioEngine::loadTrack( const Tomahawk::result_ptr& result )
|
||||
{
|
||||
setCurrentTrack( result );
|
||||
|
||||
if ( !isHttpResult( m_currentTrack->url() ) )
|
||||
if ( !isHttpResult( m_currentTrack->url() ) && !isLocalResult( m_currentTrack->url() ) )
|
||||
{
|
||||
io = Servent::instance()->getIODeviceForUrl( m_currentTrack );
|
||||
|
||||
@ -193,18 +223,7 @@ AudioEngine::loadTrack( const Tomahawk::result_ptr& result )
|
||||
qDebug() << "Starting new song from url:" << m_currentTrack->url();
|
||||
emit loading( m_currentTrack );
|
||||
|
||||
if ( !m_input.isNull() || m_isPlayingHttp )
|
||||
{
|
||||
if ( !m_input.isNull() )
|
||||
{
|
||||
m_input->close();
|
||||
m_input.clear();
|
||||
}
|
||||
|
||||
m_expectStop = true;
|
||||
}
|
||||
|
||||
if ( !isHttpResult( m_currentTrack->url() ) )
|
||||
if ( !isHttpResult( m_currentTrack->url() ) && !isLocalResult( m_currentTrack->url() ) )
|
||||
{
|
||||
m_mediaObject->setCurrentSource( io.data() );
|
||||
m_mediaObject->currentSource().setAutoDelete( false );
|
||||
@ -217,19 +236,33 @@ AudioEngine::loadTrack( const Tomahawk::result_ptr& result )
|
||||
{
|
||||
furl = QUrl( m_currentTrack->url().left( m_currentTrack->url().indexOf( '?' ) ) );
|
||||
furl.setEncodedQuery( QString( m_currentTrack->url().mid( m_currentTrack->url().indexOf( '?' ) + 1 ) ).toLocal8Bit() );
|
||||
qDebug() << Q_FUNC_INFO << furl;
|
||||
}
|
||||
m_mediaObject->setCurrentSource( furl );
|
||||
m_mediaObject->currentSource().setAutoDelete( true );
|
||||
m_isPlayingHttp = true;
|
||||
}
|
||||
|
||||
if ( !m_input.isNull() )
|
||||
{
|
||||
m_input->close();
|
||||
m_input.clear();
|
||||
}
|
||||
m_input = io;
|
||||
m_mediaObject->play();
|
||||
emit started( m_currentTrack );
|
||||
|
||||
DatabaseCommand_LogPlayback* cmd = new DatabaseCommand_LogPlayback( m_currentTrack, DatabaseCommand_LogPlayback::Started );
|
||||
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>(cmd) );
|
||||
|
||||
Tomahawk::InfoSystem::InfoCriteriaHash trackInfo;
|
||||
|
||||
trackInfo["title"] = m_currentTrack->track();
|
||||
trackInfo["artist"] = m_currentTrack->artist()->name();
|
||||
trackInfo["album"] = m_currentTrack->album()->name();
|
||||
Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo(
|
||||
s_aeInfoIdentifier, Tomahawk::InfoSystem::InfoNowPlaying,
|
||||
QVariant::fromValue< Tomahawk::InfoSystem::InfoCriteriaHash >( trackInfo ) );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -297,26 +330,37 @@ AudioEngine::playItem( PlaylistInterface* playlist, const Tomahawk::result_ptr&
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AudioEngine::onAboutToFinish()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
m_expectStop = true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AudioEngine::onStateChanged( Phonon::State newState, Phonon::State oldState )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << oldState << newState;
|
||||
qDebug() << Q_FUNC_INFO << oldState << newState << m_expectStop;
|
||||
|
||||
if ( newState == Phonon::ErrorState )
|
||||
{
|
||||
qDebug() << "Phonon Error:" << m_mediaObject->errorString() << m_mediaObject->errorType();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( oldState == Phonon::PlayingState && newState == Phonon::StoppedState )
|
||||
if ( !m_expectStop )
|
||||
return;
|
||||
m_expectStop = false;
|
||||
|
||||
if ( oldState == Phonon::PlayingState )
|
||||
{
|
||||
if ( !m_expectStop )
|
||||
if ( newState == Phonon::PausedState || newState == Phonon::StoppedState )
|
||||
{
|
||||
m_expectStop = false;
|
||||
qDebug() << "Loading next track.";
|
||||
loadNextTrack();
|
||||
}
|
||||
}
|
||||
|
||||
m_expectStop = false;
|
||||
}
|
||||
|
||||
|
||||
@ -365,8 +409,16 @@ AudioEngine::setCurrentTrack( const Tomahawk::result_ptr& result )
|
||||
m_currentTrack = result;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
AudioEngine::isHttpResult( const QString& url ) const
|
||||
{
|
||||
return url.startsWith( "http://" );
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
AudioEngine::isLocalResult( const QString& url ) const
|
||||
{
|
||||
return url.startsWith( "file://" );
|
||||
}
|
||||
|
@ -64,10 +64,11 @@ public slots:
|
||||
void previous();
|
||||
void next();
|
||||
|
||||
void seek( int ms );
|
||||
void setVolume( int percentage );
|
||||
void lowerVolume() { setVolume( volume() - AUDIO_VOLUME_STEP ); }
|
||||
void raiseVolume() { setVolume( volume() + AUDIO_VOLUME_STEP ); }
|
||||
void onVolumeChanged( float volume ) { emit volumeChanged( volume * 100 ); }
|
||||
void onVolumeChanged( qreal volume ) { emit volumeChanged( volume * 100 ); }
|
||||
void mute();
|
||||
|
||||
void playItem( PlaylistInterface* playlist, const Tomahawk::result_ptr& result );
|
||||
@ -99,6 +100,7 @@ private slots:
|
||||
void loadPreviousTrack();
|
||||
void loadNextTrack();
|
||||
|
||||
void onAboutToFinish();
|
||||
void onStateChanged( Phonon::State newState, Phonon::State oldState );
|
||||
void timerTriggered( qint64 time );
|
||||
|
||||
@ -106,6 +108,7 @@ private slots:
|
||||
|
||||
private:
|
||||
bool isHttpResult( const QString& ) const;
|
||||
bool isLocalResult( const QString& ) const;
|
||||
|
||||
bool m_isPlayingHttp;
|
||||
QSharedPointer<QIODevice> m_input;
|
||||
|
@ -1,63 +0,0 @@
|
||||
/*
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) 2011 Leo Franchi <leo@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 DUMMYTRANSCODE_H
|
||||
#define DUMMYTRANSCODE_H
|
||||
|
||||
#include "audio/transcodeinterface.h"
|
||||
#include "dllmacro.h"
|
||||
|
||||
#define _BUFFER_PREFERRED 32768
|
||||
|
||||
class DLLEXPORT DummyTranscode : public TranscodeInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DummyTranscode();
|
||||
virtual ~DummyTranscode();
|
||||
|
||||
const QStringList supportedTypes() const { QStringList l; l << "audio/basic"; return l; }
|
||||
|
||||
int needData() { return true; } // always eats data
|
||||
bool haveData() { return !m_buffer.isEmpty(); }
|
||||
|
||||
unsigned int preferredDataSize() { return _BUFFER_PREFERRED; }
|
||||
|
||||
QByteArray data() { QByteArray b = m_buffer; m_buffer.clear(); return b; }
|
||||
|
||||
virtual void setBufferCapacity( int bytes ) { m_bufferCapacity = bytes; }
|
||||
int bufferSize() { return m_buffer.size(); }
|
||||
|
||||
public slots:
|
||||
virtual void clearBuffers();
|
||||
virtual void onSeek( int seconds );
|
||||
virtual void processData( const QByteArray& data, bool finish );
|
||||
|
||||
signals:
|
||||
void streamInitialized( long sampleRate, int channels );
|
||||
void timeChanged( int seconds );
|
||||
|
||||
private:
|
||||
QByteArray m_buffer;
|
||||
int m_bufferCapacity;
|
||||
bool m_init;
|
||||
};
|
||||
|
||||
#endif // DUMMYTRANSCODE_H
|
@ -36,23 +36,35 @@ DatabaseCommand_Resolve::DatabaseCommand_Resolve( const query_ptr& query )
|
||||
void
|
||||
DatabaseCommand_Resolve::exec( DatabaseImpl* lib )
|
||||
{
|
||||
QList<Tomahawk::result_ptr> res;
|
||||
if ( !m_query->resultHint().isEmpty() )
|
||||
{
|
||||
qDebug() << "Using result-hint to speed up resolving:" << m_query->resultHint();
|
||||
|
||||
Tomahawk::result_ptr result = lib->resultFromHint( m_query );
|
||||
/* qDebug() << "Result null:" << result.isNull();
|
||||
qDebug() << "Collection null:" << result->collection().isNull();
|
||||
qDebug() << "Source null:" << result->collection()->source().isNull();*/
|
||||
/* qDebug() << "Result null:" << result.isNull();
|
||||
* qDebug() << "Collection null:" << result->collection().isNull();
|
||||
* qDebug() << "Source null:" << result->collection()->source().isNull();*/
|
||||
if ( !result.isNull() && !result->collection().isNull() && result->collection()->source()->isOnline() )
|
||||
{
|
||||
QList<Tomahawk::result_ptr> res;
|
||||
res << result;
|
||||
emit results( m_query->id(), res );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ( m_query->isFullTextQuery() )
|
||||
fullTextResolve( lib );
|
||||
else
|
||||
resolve( lib );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DatabaseCommand_Resolve::resolve( DatabaseImpl* lib )
|
||||
{
|
||||
QList<Tomahawk::result_ptr> res;
|
||||
|
||||
/*
|
||||
Resolving is a 2 stage process.
|
||||
1) find list of trk/art/alb IDs that are reasonable matches to the metadata given
|
||||
@ -64,10 +76,10 @@ DatabaseCommand_Resolve::exec( DatabaseImpl* lib )
|
||||
|
||||
// STEP 1
|
||||
QList< int > artists = lib->searchTable( "artist", m_query->artist(), 10 );
|
||||
QList< int > tracks = lib->searchTable( "track", m_query->track(), 10 );
|
||||
QList< int > albums = lib->searchTable( "album", m_query->album(), 10 );
|
||||
QList< int > tracks = lib->searchTable( "track", m_query->track(), 10 );
|
||||
QList< int > albums = lib->searchTable( "album", m_query->album(), 10 );
|
||||
|
||||
if( artists.length() == 0 || tracks.length() == 0 )
|
||||
if ( artists.length() == 0 || tracks.length() == 0 )
|
||||
{
|
||||
qDebug() << "No candidates found in first pass, aborting resolve" << m_query->artist() << m_query->track();
|
||||
emit results( m_query->id(), res );
|
||||
@ -83,6 +95,9 @@ DatabaseCommand_Resolve::exec( DatabaseImpl* lib )
|
||||
foreach( int i, tracks )
|
||||
trksl.append( QString::number( i ) );
|
||||
|
||||
QString artsToken = QString( "file_join.artist IN (%1)" ).arg( artsl.join( "," ) );
|
||||
QString trksToken = QString( "file_join.track IN (%1)" ).arg( trksl.join( "," ) );
|
||||
|
||||
QString sql = QString( "SELECT "
|
||||
"url, mtime, size, md5, mimetype, duration, bitrate, file_join.artist, file_join.album, file_join.track, "
|
||||
"artist.name as artname, "
|
||||
@ -98,10 +113,9 @@ DatabaseCommand_Resolve::exec( DatabaseImpl* lib )
|
||||
"artist.id = file_join.artist AND "
|
||||
"track.id = file_join.track AND "
|
||||
"file.id = file_join.file AND "
|
||||
"file_join.artist IN (%1) AND "
|
||||
"file_join.track IN (%2)" )
|
||||
.arg( artsl.join( "," ) )
|
||||
.arg( trksl.join( "," ) );
|
||||
"(%1 AND %2)" )
|
||||
.arg( artsToken )
|
||||
.arg( trksToken );
|
||||
|
||||
files_query.prepare( sql );
|
||||
files_query.exec();
|
||||
@ -160,7 +174,136 @@ DatabaseCommand_Resolve::exec( DatabaseImpl* lib )
|
||||
|
||||
float score = how_similar( m_query, result );
|
||||
result->setScore( score );
|
||||
if( score < MINSCORE )
|
||||
if ( m_query->fullTextQuery().isEmpty() && score < MINSCORE )
|
||||
continue;
|
||||
|
||||
result->setCollection( s->collection() );
|
||||
res << result;
|
||||
}
|
||||
|
||||
emit results( m_query->id(), res );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DatabaseCommand_Resolve::fullTextResolve( DatabaseImpl* lib )
|
||||
{
|
||||
QList<Tomahawk::result_ptr> res;
|
||||
|
||||
/*
|
||||
* Resolving is a 2 stage process.
|
||||
* 1) find list of trk/art/alb IDs that are reasonable matches to the metadata given
|
||||
* 2) find files in database by permitted sources and calculate score, ignoring
|
||||
* results that are less than MINSCORE
|
||||
*/
|
||||
|
||||
typedef QPair<int, float> scorepair_t;
|
||||
|
||||
// STEP 1
|
||||
QList< int > artists = lib->searchTable( "artist", m_query->fullTextQuery(), 10 );
|
||||
QList< int > tracks = lib->searchTable( "track", m_query->fullTextQuery(), 10 );
|
||||
QList< int > albums = lib->searchTable( "album", m_query->fullTextQuery(), 10 );
|
||||
|
||||
if ( artists.length() == 0 && tracks.length() == 0 && albums.length() == 0 )
|
||||
{
|
||||
qDebug() << "No candidates found in first pass, aborting resolve" << m_query->artist() << m_query->track();
|
||||
emit results( m_query->id(), res );
|
||||
return;
|
||||
}
|
||||
|
||||
// STEP 2
|
||||
TomahawkSqlQuery files_query = lib->newquery();
|
||||
|
||||
QStringList artsl, trksl, albsl;
|
||||
foreach( int i, artists )
|
||||
artsl.append( QString::number( i ) );
|
||||
foreach( int i, tracks )
|
||||
trksl.append( QString::number( i ) );
|
||||
foreach( int i, albums )
|
||||
albsl.append( QString::number( i ) );
|
||||
|
||||
QString artsToken = QString( "file_join.artist IN (%1)" ).arg( artsl.join( "," ) );
|
||||
QString trksToken = QString( "file_join.track IN (%1)" ).arg( trksl.join( "," ) );
|
||||
QString albsToken = QString( "file_join.album IN (%1)" ).arg( albsl.join( "," ) );
|
||||
|
||||
QString sql = QString( "SELECT "
|
||||
"url, mtime, size, md5, mimetype, duration, bitrate, file_join.artist, file_join.album, file_join.track, "
|
||||
"artist.name as artname, "
|
||||
"album.name as albname, "
|
||||
"track.name as trkname, "
|
||||
"file.source, "
|
||||
"file_join.albumpos, "
|
||||
"artist.id as artid, "
|
||||
"album.id as albid "
|
||||
"FROM file, file_join, artist, track "
|
||||
"LEFT JOIN album ON album.id = file_join.album "
|
||||
"WHERE "
|
||||
"artist.id = file_join.artist AND "
|
||||
"track.id = file_join.track AND "
|
||||
"file.id = file_join.file AND "
|
||||
"(%1 OR %2 OR %3)" )
|
||||
.arg( artists.length() > 0 ? artsToken : QString( "0" ) )
|
||||
.arg( tracks.length() > 0 ? trksToken : QString( "0" ) )
|
||||
.arg( albums.length() > 0 ? albsToken : QString( "0" ) );
|
||||
|
||||
files_query.prepare( sql );
|
||||
files_query.exec();
|
||||
|
||||
while( files_query.next() )
|
||||
{
|
||||
Tomahawk::result_ptr result( new Tomahawk::Result() );
|
||||
source_ptr s;
|
||||
|
||||
const QString url_str = files_query.value( 0 ).toString();
|
||||
if( files_query.value( 13 ).toUInt() == 0 )
|
||||
{
|
||||
s = SourceList::instance()->getLocal();
|
||||
result->setUrl( url_str );
|
||||
}
|
||||
else
|
||||
{
|
||||
s = SourceList::instance()->get( files_query.value( 13 ).toUInt() );
|
||||
if( s.isNull() )
|
||||
{
|
||||
qDebug() << "WTF: Could not find source" << files_query.value( 13 ).toUInt();
|
||||
continue;
|
||||
}
|
||||
|
||||
result->setUrl( QString( "servent://%1\t%2" ).arg( s->userName() ).arg( url_str ) );
|
||||
}
|
||||
|
||||
Tomahawk::artist_ptr artist = Tomahawk::Artist::get( files_query.value( 15 ).toUInt(), files_query.value( 10 ).toString() );
|
||||
Tomahawk::album_ptr album = Tomahawk::Album::get( files_query.value( 16 ).toUInt(), files_query.value( 11 ).toString(), artist );
|
||||
|
||||
result->setModificationTime( files_query.value( 1 ).toUInt() );
|
||||
result->setSize( files_query.value( 2 ).toUInt() );
|
||||
result->setMimetype( files_query.value( 4 ).toString() );
|
||||
result->setDuration( files_query.value( 5 ).toUInt() );
|
||||
result->setBitrate( files_query.value( 6 ).toUInt() );
|
||||
result->setArtist( artist );
|
||||
result->setAlbum( album );
|
||||
result->setTrack( files_query.value( 12 ).toString() );
|
||||
result->setRID( uuid() );
|
||||
result->setAlbumPos( files_query.value( 14 ).toUInt() );
|
||||
result->setId( files_query.value( 9 ).toUInt() );
|
||||
result->setYear( files_query.value( 17 ).toUInt() );
|
||||
|
||||
TomahawkSqlQuery attrQuery = lib->newquery();
|
||||
QVariantMap attr;
|
||||
|
||||
attrQuery.prepare( "SELECT k, v FROM track_attributes WHERE id = ?" );
|
||||
attrQuery.bindValue( 0, result->dbid() );
|
||||
attrQuery.exec();
|
||||
while ( attrQuery.next() )
|
||||
{
|
||||
attr[ attrQuery.value( 0 ).toString() ] = attrQuery.value( 1 ).toString();
|
||||
}
|
||||
|
||||
result->setAttributes( attr );
|
||||
|
||||
float score = how_similar( m_query, result );
|
||||
result->setScore( score );
|
||||
if ( m_query->fullTextQuery().isEmpty() && score < MINSCORE )
|
||||
continue;
|
||||
|
||||
result->setCollection( s->collection() );
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
@ -44,6 +44,9 @@ signals:
|
||||
public slots:
|
||||
|
||||
private:
|
||||
void fullTextResolve( DatabaseImpl* lib );
|
||||
void resolve( DatabaseImpl* lib );
|
||||
|
||||
Tomahawk::query_ptr m_query;
|
||||
|
||||
float how_similar( const Tomahawk::query_ptr& q, const Tomahawk::result_ptr& r );
|
||||
|
@ -60,7 +60,6 @@ GlobalActionManager::~GlobalActionManager()
|
||||
QUrl
|
||||
GlobalActionManager::openLinkFromQuery( const Tomahawk::query_ptr& query ) const
|
||||
{
|
||||
QUrl link( "tomahawk://open/track/" );
|
||||
QString title, artist, album;
|
||||
|
||||
if( !query->results().isEmpty() && !query->results().first().isNull() )
|
||||
@ -75,6 +74,14 @@ GlobalActionManager::openLinkFromQuery( const Tomahawk::query_ptr& query ) const
|
||||
album = query->album();
|
||||
}
|
||||
|
||||
return openLink( title, artist, album );
|
||||
}
|
||||
|
||||
QUrl
|
||||
GlobalActionManager::openLink( const QString& title, const QString& artist, const QString& album, bool tomahk ) const
|
||||
{
|
||||
QUrl link( tomahk ? "http://toma.hk/open/track/" : "tomahawk://open/track/" );
|
||||
|
||||
if( !title.isEmpty() )
|
||||
link.addQueryItem( "title", title );
|
||||
if( !artist.isEmpty() )
|
||||
@ -85,14 +92,14 @@ GlobalActionManager::openLinkFromQuery( const Tomahawk::query_ptr& query ) const
|
||||
return link;
|
||||
}
|
||||
|
||||
void
|
||||
QString
|
||||
GlobalActionManager::copyPlaylistToClipboard( const Tomahawk::dynplaylist_ptr& playlist )
|
||||
{
|
||||
QUrl link( QString( "tomahawk://%1/create/" ).arg( playlist->mode() == Tomahawk::OnDemand ? "station" : "autoplaylist" ) );
|
||||
|
||||
if( playlist->generator()->type() != "echonest" ) {
|
||||
qDebug() << "Only echonest generators are supported";
|
||||
return;
|
||||
return QString();
|
||||
}
|
||||
|
||||
link.addEncodedQueryItem( "type", "echonest" );
|
||||
@ -123,6 +130,8 @@ GlobalActionManager::copyPlaylistToClipboard( const Tomahawk::dynplaylist_ptr& p
|
||||
|
||||
QClipboard* cb = QApplication::clipboard();
|
||||
cb->setText( link.toEncoded() );
|
||||
|
||||
return link.toString();
|
||||
}
|
||||
|
||||
void
|
||||
@ -165,10 +174,11 @@ GlobalActionManager::parseTomahawkLink( const QString& url )
|
||||
{
|
||||
if( url.contains( "tomahawk://" ) ) {
|
||||
QString cmd = url.mid( 11 );
|
||||
cmd.replace( "%2B", "%20" );
|
||||
qDebug() << "Parsing tomahawk link command" << cmd;
|
||||
|
||||
QString cmdType = cmd.split( "/" ).first();
|
||||
QUrl u( cmd );
|
||||
QUrl u = QUrl::fromEncoded( cmd.toUtf8() );
|
||||
|
||||
// for backwards compatibility
|
||||
if( cmdType == "load" ) {
|
||||
@ -380,22 +390,22 @@ GlobalActionManager::handleSearchCommand( const QUrl& url )
|
||||
bool
|
||||
GlobalActionManager::handleAutoPlaylistCommand( const QUrl& url )
|
||||
{
|
||||
return loadDynamicPlaylist( url, false );
|
||||
return !loadDynamicPlaylist( url, false ).isNull();
|
||||
}
|
||||
|
||||
bool
|
||||
Tomahawk::dynplaylist_ptr
|
||||
GlobalActionManager::loadDynamicPlaylist( const QUrl& url, bool station )
|
||||
{
|
||||
QStringList parts = url.path().split( "/" ).mid( 1 ); // get the rest of the command
|
||||
if( parts.isEmpty() ) {
|
||||
qDebug() << "No specific station command:" << url.toString();
|
||||
return false;
|
||||
return Tomahawk::dynplaylist_ptr();
|
||||
}
|
||||
|
||||
if( parts[ 0 ] == "create" ) {
|
||||
if( !url.hasQueryItem( "title" ) || !url.hasQueryItem( "type" ) ) {
|
||||
qDebug() << "Station create command needs title and type..." << url.toString();
|
||||
return false;
|
||||
return Tomahawk::dynplaylist_ptr();
|
||||
}
|
||||
QString title = url.queryItemValue( "title" );
|
||||
QString type = url.queryItemValue( "type" );
|
||||
@ -520,17 +530,17 @@ GlobalActionManager::loadDynamicPlaylist( const QUrl& url, bool station )
|
||||
else
|
||||
pl->createNewRevision( uuid(), pl->currentrevision(), type, controls, pl->entries() );
|
||||
|
||||
return true;
|
||||
return pl;
|
||||
}
|
||||
|
||||
return false;
|
||||
return Tomahawk::dynplaylist_ptr();
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
GlobalActionManager::handleStationCommand( const QUrl& url )
|
||||
{
|
||||
return loadDynamicPlaylist( url, true );
|
||||
return !loadDynamicPlaylist( url, true ).isNull();
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -36,15 +36,17 @@ public:
|
||||
virtual ~GlobalActionManager();
|
||||
|
||||
QUrl openLinkFromQuery( const Tomahawk::query_ptr& query ) const;
|
||||
QUrl openLink( const QString& title, const QString& artist, const QString& album, bool tomahk=false ) const;
|
||||
|
||||
void copyToClipboard( const Tomahawk::query_ptr& query ) const;
|
||||
void copyPlaylistToClipboard( const Tomahawk::dynplaylist_ptr& playlist );
|
||||
QString copyPlaylistToClipboard( const Tomahawk::dynplaylist_ptr& playlist );
|
||||
void savePlaylistToFile( const Tomahawk::playlist_ptr& playlist, const QString& filename );
|
||||
|
||||
public slots:
|
||||
bool parseTomahawkLink( const QString& link );
|
||||
void waitingForResolved( bool );
|
||||
|
||||
Tomahawk::dynplaylist_ptr loadDynamicPlaylist( const QUrl& url, bool station );
|
||||
private slots:
|
||||
void bookmarkPlaylistCreated( const Tomahawk::playlist_ptr& pl );
|
||||
void showPlaylist();
|
||||
@ -65,7 +67,6 @@ private:
|
||||
bool handleBookmarkCommand(const QUrl& url );
|
||||
bool handleOpenCommand(const QUrl& url );
|
||||
|
||||
bool loadDynamicPlaylist( const QUrl& url, bool station );
|
||||
bool doQueueAdd( const QStringList& parts, const QList< QPair< QString, QString > >& queryItems );
|
||||
|
||||
Tomahawk::playlist_ptr m_toShow;
|
||||
|
25
src/libtomahawk/infosystem/infoplugins/adium.h
Normal file
25
src/libtomahawk/infosystem/infoplugins/adium.h
Normal file
@ -0,0 +1,25 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ADIUM_TOMAHAWK_H
|
||||
#define ADIUM_TOMAHAWK_H
|
||||
#include <string>
|
||||
|
||||
void script( const char* status );
|
||||
|
||||
#endif ADIUM_TOMAHAWK_H
|
@ -1,5 +1,5 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
@ -16,28 +16,16 @@
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#import <AppKit/NSApplication.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <ScriptingBridge/ScriptingBridge.h>
|
||||
#import "adium.h"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
// this file copied and inspired by mac_startup.* in clementine player,
|
||||
// copyright David Sansome 2010
|
||||
namespace Tomahawk {
|
||||
class PlatformInterface;
|
||||
void
|
||||
script( const char* status )
|
||||
{
|
||||
NSString *stat = [NSString stringWithUTF8String:status];
|
||||
NSAppleScript *appleScript = [[NSAppleScript alloc] initWithSource:stat];
|
||||
NSDictionary *errorDictionary;
|
||||
NSAppleEventDescriptor *eventDescriptor = [appleScript executeAndReturnError:&errorDictionary];
|
||||
[appleScript release];
|
||||
}
|
||||
|
||||
#ifdef SNOW_LEOPARD
|
||||
@interface AppDelegate : NSObject <NSApplicationDelegate> {
|
||||
#else
|
||||
@interface AppDelegate : NSObject {
|
||||
#endif
|
||||
Tomahawk::PlatformInterface* application_handler_;
|
||||
//NSMenu* dock_menu_;
|
||||
}
|
||||
|
||||
- (id) initWithHandler: (Tomahawk::PlatformInterface*)handler;
|
||||
// NSApplicationDelegate
|
||||
- (BOOL) applicationShouldHandleReopen: (NSApplication*)app hasVisibleWindows:(BOOL)flag;
|
||||
//- (NSMenu*) applicationDockMenu: (NSApplication*)sender;
|
||||
//- (void) setDockMenu: (NSMenu*)menu;
|
||||
@end
|
190
src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp
Normal file
190
src/libtomahawk/infosystem/infoplugins/adiumplugin.cpp
Normal file
@ -0,0 +1,190 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "infosystem/infosystemworker.h"
|
||||
#include "artist.h"
|
||||
#include "result.h"
|
||||
#include "tomahawksettings.h"
|
||||
#include "globalactionmanager.h"
|
||||
|
||||
#include "adiumplugin.h"
|
||||
#include "adium.h"
|
||||
|
||||
QString adium_beforeStatus;
|
||||
QString adium_afterStatus;
|
||||
|
||||
static void setStatus(const QString &status)
|
||||
{
|
||||
// The command that updates the status
|
||||
QString scriptqstr;
|
||||
scriptqstr.append(adium_beforeStatus);
|
||||
scriptqstr.append(status);
|
||||
scriptqstr.append(adium_afterStatus);
|
||||
|
||||
const char* scriptstr = scriptqstr.toUtf8();
|
||||
script( scriptstr );
|
||||
}
|
||||
|
||||
using namespace Tomahawk::InfoSystem;
|
||||
|
||||
AdiumPlugin::AdiumPlugin()
|
||||
: InfoPlugin()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
|
||||
adium_beforeStatus = "if appIsRunning(\"Adium\") then\n";
|
||||
adium_beforeStatus.append("tell application \"Adium\"\n");
|
||||
adium_beforeStatus.append("set the status message of every account to \"");
|
||||
|
||||
adium_afterStatus.append("\"\nend tell\n");
|
||||
adium_afterStatus.append("end if\n");
|
||||
adium_afterStatus.append("on appIsRunning(appName)\n");
|
||||
adium_afterStatus.append("tell application \"System Events\" to (name of processes) contains appName\n");
|
||||
adium_afterStatus.append("end appIsRunning\n");
|
||||
|
||||
m_supportedPushTypes << InfoNowPlaying << InfoNowPaused << InfoNowResumed << InfoNowStopped;
|
||||
|
||||
m_active = TomahawkSettings::instance()->nowPlayingEnabled();
|
||||
|
||||
connect( TomahawkSettings::instance(), SIGNAL( changed() ),
|
||||
SLOT( settingsChanged() ), Qt::QueuedConnection );
|
||||
}
|
||||
|
||||
AdiumPlugin::~AdiumPlugin()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
setStatus( "" );
|
||||
}
|
||||
|
||||
void
|
||||
AdiumPlugin::settingsChanged()
|
||||
{
|
||||
m_active = TomahawkSettings::instance()->nowPlayingEnabled();
|
||||
if( !m_active )
|
||||
setStatus( "" );
|
||||
}
|
||||
|
||||
void
|
||||
AdiumPlugin::getInfo( const QString caller, const InfoType type, const QVariant data, InfoCustomData customData )
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
default:
|
||||
{
|
||||
emit info(caller, Tomahawk::InfoSystem::InfoNoInfo, QVariant(), QVariant(), customData);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AdiumPlugin::pushInfo( const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
|
||||
if( !m_active )
|
||||
return;
|
||||
|
||||
switch ( type )
|
||||
{
|
||||
case InfoNowPlaying:
|
||||
audioStarted( input );
|
||||
break;
|
||||
// case InfoNowPaused:
|
||||
// audioPaused();
|
||||
// break;
|
||||
case InfoNowResumed:
|
||||
audioResumed( input );
|
||||
break;
|
||||
case InfoNowStopped:
|
||||
audioStopped();
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/** Audio state slots */
|
||||
void
|
||||
AdiumPlugin::audioStarted( const QVariant &input )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
|
||||
if ( !input.canConvert< Tomahawk::InfoSystem::InfoCriteriaHash >() )
|
||||
return;
|
||||
|
||||
InfoCriteriaHash hash = input.value< Tomahawk::InfoSystem::InfoCriteriaHash >();
|
||||
if ( !hash.contains( "title" ) || !hash.contains( "artist" ) )
|
||||
return;
|
||||
|
||||
QString nowPlaying = "";
|
||||
nowPlaying.append( hash["title"] );
|
||||
nowPlaying.append(" - ");
|
||||
nowPlaying.append( hash["artist"] );
|
||||
nowPlaying.append( " " );
|
||||
nowPlaying.append( openLinkFromHash( hash ).toEncoded() );
|
||||
setStatus( nowPlaying );
|
||||
}
|
||||
|
||||
QUrl
|
||||
AdiumPlugin::openLinkFromHash( const Tomahawk::InfoSystem::InfoCriteriaHash& hash ) const
|
||||
{
|
||||
QString title, artist, album;
|
||||
|
||||
if( !hash.isEmpty() && hash.contains( "title" ) && hash.contains( "artist" ) )
|
||||
{
|
||||
title = hash["title"];
|
||||
artist = hash["artist"];
|
||||
if( hash.contains( "album" ) )
|
||||
album = hash["album"];
|
||||
}
|
||||
|
||||
return GlobalActionManager::instance()->openLink( title, artist, album, true );
|
||||
}
|
||||
|
||||
void
|
||||
AdiumPlugin::audioFinished( const QVariant &input )
|
||||
{
|
||||
//qDebug() << Q_FUNC_INFO;
|
||||
}
|
||||
|
||||
void
|
||||
AdiumPlugin::audioStopped()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
setStatus( "" );
|
||||
}
|
||||
|
||||
void
|
||||
AdiumPlugin::audioPaused()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
|
||||
//setStatus( "Paused" );
|
||||
}
|
||||
|
||||
void
|
||||
AdiumPlugin::audioResumed( const QVariant &input )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
// TODO: audio resumed, so push update status to Adium with playing track
|
||||
audioStarted( input );
|
||||
}
|
69
src/libtomahawk/infosystem/infoplugins/adiumplugin.h
Normal file
69
src/libtomahawk/infosystem/infoplugins/adiumplugin.h
Normal file
@ -0,0 +1,69 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ADIUMPLUGIN_H
|
||||
#define ADIUMPLUGIN_H
|
||||
|
||||
#include "infosystem/infosystem.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QVariant>
|
||||
|
||||
namespace Tomahawk {
|
||||
|
||||
namespace InfoSystem {
|
||||
|
||||
class AdiumPlugin : public InfoPlugin
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AdiumPlugin();
|
||||
virtual ~AdiumPlugin();
|
||||
|
||||
protected slots:
|
||||
void getInfo( const QString caller, const InfoType type, const QVariant data, InfoCustomData customData );
|
||||
void pushInfo( const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input );
|
||||
|
||||
public slots:
|
||||
void namChangedSlot( QNetworkAccessManager *nam ) {} // unused
|
||||
void notInCacheSlot( const Tomahawk::InfoSystem::InfoCriteriaHash criteria, const QString caller, const Tomahawk::InfoSystem::InfoType type, const QVariant input, const Tomahawk::InfoSystem::InfoCustomData customData ) {} // unused
|
||||
|
||||
private:
|
||||
void settingsChanged();
|
||||
|
||||
void audioStarted( const QVariant &input );
|
||||
void audioFinished( const QVariant &input );
|
||||
void audioStopped();
|
||||
void audioPaused();
|
||||
void audioResumed( const QVariant &input );
|
||||
|
||||
QUrl openLinkFromHash( const InfoCriteriaHash& hash ) const;
|
||||
|
||||
bool m_active;
|
||||
QString m_beforeStatus;
|
||||
QString m_afterStatus;
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // ADIUMPLUGIN_H
|
@ -25,6 +25,7 @@
|
||||
#include "infoplugins/echonestplugin.h"
|
||||
#include "infoplugins/musixmatchplugin.h"
|
||||
#include "infoplugins/lastfmplugin.h"
|
||||
#include "infoplugins/adiumplugin.h"
|
||||
|
||||
namespace Tomahawk
|
||||
{
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <QtCore/QWeakPointer>
|
||||
#include <QtCore/QSet>
|
||||
#include <QtCore/QLinkedList>
|
||||
#include <QtCore/QUrl>
|
||||
#include <QtCore/QVariant>
|
||||
#include <QtCore/QThread>
|
||||
|
||||
@ -94,7 +95,12 @@ enum InfoType { // as items are saved in cache, mark them here to not change the
|
||||
InfoSubmitNowPlaying = 46,
|
||||
InfoSubmitScrobble = 47,
|
||||
|
||||
InfoNoInfo = 48
|
||||
InfoNowPlaying = 48,
|
||||
InfoNowPaused = 49,
|
||||
InfoNowResumed = 50,
|
||||
InfoNowStopped = 51,
|
||||
|
||||
InfoNoInfo = 52
|
||||
};
|
||||
|
||||
typedef QMap< InfoType, QVariant > InfoMap;
|
||||
|
@ -26,6 +26,9 @@
|
||||
#include "infoplugins/echonestplugin.h"
|
||||
#include "infoplugins/musixmatchplugin.h"
|
||||
#include "infoplugins/lastfmplugin.h"
|
||||
#ifdef Q_WS_MAC
|
||||
#include "infoplugins/adiumplugin.h"
|
||||
#endif
|
||||
|
||||
#include "lastfm/NetworkAccessManager"
|
||||
|
||||
@ -66,6 +69,11 @@ InfoSystemWorker::init( QWeakPointer< Tomahawk::InfoSystem::InfoSystemCache> cac
|
||||
InfoPluginPtr lfmptr( new LastFmPlugin() );
|
||||
m_plugins.append( lfmptr );
|
||||
registerInfoTypes( lfmptr, lfmptr.data()->supportedGetTypes(), lfmptr.data()->supportedPushTypes() );
|
||||
#ifdef Q_WS_MAC
|
||||
InfoPluginPtr admptr( new AdiumPlugin() );
|
||||
m_plugins.append( admptr );
|
||||
registerInfoTypes( admptr, admptr.data()->supportedGetTypes(), admptr.data()->supportedPushTypes() );
|
||||
#endif
|
||||
|
||||
Q_FOREACH( InfoPluginPtr plugin, m_plugins )
|
||||
{
|
||||
|
@ -82,8 +82,9 @@ void
|
||||
Pipeline::removeResolver( Resolver* r )
|
||||
{
|
||||
QMutexLocker lock( &m_mut );
|
||||
|
||||
|
||||
m_resolvers.removeAll( r );
|
||||
emit resolverRemoved( r );
|
||||
}
|
||||
|
||||
|
||||
@ -100,6 +101,7 @@ Pipeline::addResolver( Resolver* r, bool sort )
|
||||
Pipeline::resolverSorter );
|
||||
}
|
||||
qDebug() << "Adding resolver" << r->name();
|
||||
emit resolverAdded( r );
|
||||
|
||||
/* qDebug() << "Current pipeline:";
|
||||
foreach( Resolver * r, m_resolvers )
|
||||
@ -190,7 +192,7 @@ Pipeline::reportResults( QID qid, const QList< result_ptr >& results )
|
||||
m_rids.insert( r->id(), r );
|
||||
}
|
||||
|
||||
if ( q->solved() )
|
||||
if ( q->solved() && !q->isFullTextQuery() )
|
||||
{
|
||||
// qDebug() << "FINISHED RESOLVING EARLY" << q->toString();
|
||||
q->onResolvingFinished();
|
||||
@ -206,7 +208,7 @@ Pipeline::reportResults( QID qid, const QList< result_ptr >& results )
|
||||
|
||||
if ( decQIDState( q ) == 0 )
|
||||
{
|
||||
if ( !q->solved() )
|
||||
if ( !q->solved() || q->isFullTextQuery() )
|
||||
q->onResolvingFinished();
|
||||
|
||||
if ( m_qidsTimeout.contains( q->id() ) )
|
||||
@ -311,6 +313,7 @@ Pipeline::shunt( const query_ptr& q )
|
||||
|
||||
qDebug() << "Dispatching to resolver" << r->name() << q->toString() << q->solved() << q->id();
|
||||
r->resolve( q );
|
||||
emit resolving( q );
|
||||
}
|
||||
else
|
||||
break;
|
||||
|
@ -46,6 +46,9 @@ public:
|
||||
explicit Pipeline( QObject* parent = 0 );
|
||||
virtual ~Pipeline();
|
||||
|
||||
unsigned int pendingQueryCount() const { return m_queries_pending.count(); }
|
||||
unsigned int activeQueryCount() const { return m_qidsState.count(); }
|
||||
|
||||
void reportResults( QID qid, const QList< result_ptr >& results );
|
||||
|
||||
/// sorter to rank resolver priority
|
||||
@ -75,6 +78,10 @@ public slots:
|
||||
|
||||
signals:
|
||||
void idle();
|
||||
void resolving( const Tomahawk::query_ptr& query );
|
||||
|
||||
void resolverAdded( Resolver* );
|
||||
void resolverRemoved( Resolver* );
|
||||
|
||||
private slots:
|
||||
void timeoutShunt( const query_ptr& q );
|
||||
|
@ -55,6 +55,7 @@ CollectionProxyModel::lessThan( const QModelIndex& left, const QModelIndex& righ
|
||||
unsigned int bitrate1 = 0, bitrate2 = 0;
|
||||
unsigned int mtime1 = 0, mtime2 = 0;
|
||||
unsigned int id1 = 0, id2 = 0;
|
||||
unsigned int size1 = 0, size2 = 0;
|
||||
|
||||
if ( q1->numResults() )
|
||||
{
|
||||
@ -66,6 +67,7 @@ CollectionProxyModel::lessThan( const QModelIndex& left, const QModelIndex& righ
|
||||
bitrate1 = r->bitrate();
|
||||
mtime1 = r->modificationTime();
|
||||
id1 = r->dbid();
|
||||
size1 = r->size();
|
||||
}
|
||||
if ( q2->numResults() )
|
||||
{
|
||||
@ -77,9 +79,10 @@ CollectionProxyModel::lessThan( const QModelIndex& left, const QModelIndex& righ
|
||||
bitrate2 = r->bitrate();
|
||||
mtime2 = r->modificationTime();
|
||||
id2 = r->dbid();
|
||||
size2 = r->size();
|
||||
}
|
||||
|
||||
if ( left.column() == 0 ) // sort by artist
|
||||
if ( left.column() == TrackModel::Artist ) // sort by artist
|
||||
{
|
||||
if ( artist1 == artist2 )
|
||||
{
|
||||
@ -96,7 +99,7 @@ CollectionProxyModel::lessThan( const QModelIndex& left, const QModelIndex& righ
|
||||
|
||||
return QString::localeAwareCompare( artist1, artist2 ) < 0;
|
||||
}
|
||||
else if ( left.column() == 2 ) // sort by album
|
||||
else if ( left.column() == TrackModel::Album ) // sort by album
|
||||
{
|
||||
if ( album1 == album2 )
|
||||
{
|
||||
@ -108,21 +111,27 @@ CollectionProxyModel::lessThan( const QModelIndex& left, const QModelIndex& righ
|
||||
|
||||
return QString::localeAwareCompare( album1, album2 ) < 0;
|
||||
}
|
||||
else if ( left.column() == 4 ) // sort by bitrate
|
||||
else if ( left.column() == TrackModel::Bitrate ) // sort by bitrate
|
||||
{
|
||||
if ( bitrate1 == bitrate2 )
|
||||
return id1 < id2;
|
||||
|
||||
return bitrate1 < bitrate2;
|
||||
}
|
||||
else if ( left.column() == 5 ) // sort by mtime
|
||||
else if ( left.column() == TrackModel::Age ) // sort by mtime
|
||||
{
|
||||
if ( mtime1 == mtime2 )
|
||||
return id1 < id2;
|
||||
|
||||
return mtime1 < mtime2;
|
||||
}
|
||||
else if ( left.column() == TrackModel::Filesize ) // sort by file size
|
||||
{
|
||||
if ( size1 == size2 )
|
||||
return id1 < id2;
|
||||
|
||||
return size1 < size2;
|
||||
}
|
||||
return QString::localeAwareCompare( sourceModel()->data( left ).toString(),
|
||||
sourceModel()->data( right ).toString() ) < 0;
|
||||
}
|
||||
|
@ -30,10 +30,11 @@
|
||||
#include <qstringlistmodel.h>
|
||||
|
||||
QHash< QString, QStringList > Tomahawk::EchonestControl::s_suggestCache = QHash< QString, QStringList >();
|
||||
bool Tomahawk::EchonestControl::s_fetchingMoodsAndStyles = false;
|
||||
int Tomahawk::EchonestControl::s_stylePollCount = 0;
|
||||
|
||||
Tomahawk::EchonestControl::EchonestControl( const QString& selectedType, const QStringList& typeSelectors, QObject* parent )
|
||||
: DynamicControl ( selectedType.isEmpty() ? "Artist" : selectedType, typeSelectors, parent )
|
||||
, m_stylePollCount( 0 )
|
||||
{
|
||||
setType( "echonest" );
|
||||
m_editingTimer.setInterval( 500 ); //timeout to edits
|
||||
@ -643,7 +644,7 @@ Tomahawk::EchonestControl::calculateSummary()
|
||||
summary = QString( "similar to ~%1" ).arg( m_data.second.toString() );
|
||||
} else if( selectedType() == "Artist Description" ) {
|
||||
summary = QString( "with genre ~%1" ).arg( m_data.second.toString() );
|
||||
} else if( selectedType() == "Artist Description" ) {
|
||||
} else if( selectedType() == "Artist Description" || selectedType() == "Song" ) {
|
||||
summary = QString( "similar to ~%1" ).arg( m_data.second.toString() );
|
||||
} else if( selectedType() == "Variety" || selectedType() == "Danceability" || selectedType() == "Artist Hotttnesss" || selectedType() == "Energy" || selectedType() == "Artist Familiarity" || selectedType() == "Song Hotttnesss" ) {
|
||||
QString modifier;
|
||||
@ -705,6 +706,7 @@ Tomahawk::EchonestControl::calculateSummary()
|
||||
void
|
||||
Tomahawk::EchonestControl::checkForMoodsOrStylesFetched()
|
||||
{
|
||||
s_fetchingMoodsAndStyles = false;
|
||||
if( selectedType() == "Mood" || selectedType() == "Style" ) {
|
||||
QComboBox* cb = qobject_cast< QComboBox* >( m_input.data() );
|
||||
if( cb && cb->count() == 0 ) { // got nothing, so lets populate
|
||||
@ -722,16 +724,16 @@ Tomahawk::EchonestControl::insertMoodsAndStyles()
|
||||
if( !combo )
|
||||
return false;
|
||||
|
||||
qDebug() << "Inserting moods and or styles, here's the list" << src;
|
||||
foreach( const QString& item, src ) {
|
||||
combo->addItem( item, item );
|
||||
}
|
||||
|
||||
if( src.isEmpty() && !combo->count() ) {
|
||||
if( m_stylePollCount <= 20 ) { // try for 20s to get the styles...
|
||||
if( s_stylePollCount <= 20 && !s_fetchingMoodsAndStyles ) { // try for 20s to get the styles...
|
||||
s_fetchingMoodsAndStyles = true;
|
||||
QTimer::singleShot( 1000, this, SLOT( checkForMoodsOrStylesFetched() ) );
|
||||
}
|
||||
m_stylePollCount++;
|
||||
s_stylePollCount++;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -91,7 +91,8 @@ private:
|
||||
|
||||
Echonest::DynamicPlaylist::PlaylistParamData m_data;
|
||||
QVariant m_cacheData;
|
||||
int m_stylePollCount;
|
||||
static bool s_fetchingMoodsAndStyles;
|
||||
static int s_stylePollCount;
|
||||
|
||||
QSet< QNetworkReply* > m_suggestWorkers;
|
||||
static QHash< QString, QStringList > s_suggestCache;
|
||||
|
@ -26,6 +26,8 @@ using namespace Tomahawk;
|
||||
|
||||
QVector< QString > EchonestGenerator::s_moods = QVector< QString >();
|
||||
QVector< QString > EchonestGenerator::s_styles = QVector< QString >();
|
||||
QNetworkReply* EchonestGenerator::s_moodsJob = 0;
|
||||
QNetworkReply* EchonestGenerator::s_stylesJob = 0;
|
||||
|
||||
EchonestFactory::EchonestFactory()
|
||||
{}
|
||||
@ -59,12 +61,14 @@ EchonestGenerator::EchonestGenerator ( QObject* parent )
|
||||
m_mode = OnDemand;
|
||||
m_logo.load( RESPATH "/images/echonest_logo.png" );
|
||||
|
||||
// fetch style and moods
|
||||
QNetworkReply* style = Echonest::Artist::listTerms( "style" );
|
||||
connect( style, SIGNAL( finished() ), this, SLOT( stylesReceived() ) );
|
||||
|
||||
QNetworkReply* moods = Echonest::Artist::listTerms( "mood" );
|
||||
connect( moods, SIGNAL( finished() ), this, SLOT( moodsReceived() ) );
|
||||
if( !s_stylesJob && s_styles.isEmpty() ) {
|
||||
// fetch style and moods
|
||||
s_stylesJob = Echonest::Artist::listTerms( "style" );
|
||||
connect( s_stylesJob, SIGNAL( finished() ), this, SLOT( stylesReceived() ) );
|
||||
} else if( !s_moodsJob && s_moods.isEmpty() ) {
|
||||
s_moodsJob = Echonest::Artist::listTerms( "mood" );
|
||||
connect( s_moodsJob, SIGNAL( finished() ), this, SLOT( moodsReceived() ) );
|
||||
}
|
||||
|
||||
// qDebug() << "ECHONEST:" << m_logo.size();
|
||||
}
|
||||
@ -445,10 +449,10 @@ EchonestGenerator::sentenceSummary()
|
||||
|
||||
/// Skip empty artists
|
||||
QList< dyncontrol_ptr > empty;
|
||||
foreach( const dyncontrol_ptr& artist, required ) {
|
||||
QString summary = artist.dynamicCast< EchonestControl >()->summary();
|
||||
foreach( const dyncontrol_ptr& artistOrTrack, required ) {
|
||||
QString summary = artistOrTrack.dynamicCast< EchonestControl >()->summary();
|
||||
if( summary.lastIndexOf( "~" ) == summary.length() - 1 )
|
||||
empty << artist;
|
||||
empty << artistOrTrack;
|
||||
}
|
||||
foreach( const dyncontrol_ptr& toremove, empty ) {
|
||||
required.removeAll( toremove );
|
||||
@ -530,6 +534,7 @@ EchonestGenerator::moodsReceived()
|
||||
} catch( Echonest::ParseError& e ) {
|
||||
qWarning() << "Echonest failed to parse moods list";
|
||||
}
|
||||
s_moodsJob = 0;
|
||||
}
|
||||
|
||||
QVector< QString >
|
||||
@ -549,4 +554,5 @@ EchonestGenerator::stylesReceived()
|
||||
} catch( Echonest::ParseError& e ) {
|
||||
qWarning() << "Echonest failed to parse styles list";
|
||||
}
|
||||
s_stylesJob = 0;
|
||||
}
|
||||
|
@ -95,6 +95,8 @@ private:
|
||||
|
||||
static QVector< QString > s_styles;
|
||||
static QVector< QString > s_moods;
|
||||
static QNetworkReply* s_stylesJob;
|
||||
static QNetworkReply* s_moodsJob;
|
||||
|
||||
// used for the intermediary song id lookup
|
||||
QSet< QNetworkReply* > m_waiting;
|
||||
|
@ -99,6 +99,7 @@ PlaylistView::setupMenus()
|
||||
|
||||
foreach( QAction* a, actions() )
|
||||
m_itemMenu.addAction( a );
|
||||
|
||||
// m_addItemsToPlaylistAction = m_itemMenu.addAction( tr( "&Add to Playlist" ) );
|
||||
// m_itemMenu.addSeparator();
|
||||
m_deleteItemsAction = m_itemMenu.addAction( i > 1 ? tr( "&Delete Items" ) : tr( "&Delete Item" ) );
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
@ -45,7 +45,7 @@ QueueView::QueueView( AnimatedSplitter* parent )
|
||||
m_queue->setFrameShape( QFrame::NoFrame );
|
||||
m_queue->setAttribute( Qt::WA_MacShowFocusRect, 0 );
|
||||
m_queue->overlay()->setEnabled( false );
|
||||
|
||||
|
||||
m_button = new QPushButton();
|
||||
m_button->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed );
|
||||
m_button->setText( tr( "Click to show queue" ) );
|
||||
@ -64,13 +64,13 @@ QueueView::~QueueView()
|
||||
|
||||
|
||||
void
|
||||
QueueView::onShown( QWidget* widget )
|
||||
QueueView::onShown( QWidget* widget, bool animated )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << widget;
|
||||
if ( widget != this )
|
||||
return;
|
||||
|
||||
AnimatedWidget::onShown( widget );
|
||||
AnimatedWidget::onShown( widget, animated );
|
||||
|
||||
m_button->setText( tr( "Click to hide queue" ) );
|
||||
disconnect( m_button, SIGNAL( clicked() ), this, SIGNAL( showWidget() ) );
|
||||
@ -79,14 +79,14 @@ QueueView::onShown( QWidget* widget )
|
||||
|
||||
|
||||
void
|
||||
QueueView::onHidden( QWidget* widget )
|
||||
QueueView::onHidden( QWidget* widget, bool animated )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << widget;
|
||||
if ( widget != this )
|
||||
return;
|
||||
|
||||
AnimatedWidget::onHidden( widget );
|
||||
|
||||
|
||||
AnimatedWidget::onHidden( widget, animated );
|
||||
|
||||
m_button->setText( tr( "Click to show queue" ) );
|
||||
disconnect( m_button, SIGNAL( clicked() ), this, SIGNAL( hideWidget() ) );
|
||||
connect( m_button, SIGNAL( clicked() ), SIGNAL( showWidget() ) );
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
@ -39,8 +39,8 @@ public:
|
||||
QSize sizeHint() const { return QSize( 0, 200 ); }
|
||||
|
||||
public slots:
|
||||
virtual void onShown( QWidget* );
|
||||
virtual void onHidden( QWidget* );
|
||||
virtual void onShown( QWidget*, bool animated );
|
||||
virtual void onHidden( QWidget*, bool animated );
|
||||
|
||||
private:
|
||||
PlaylistView* m_queue;
|
||||
|
@ -33,7 +33,7 @@
|
||||
|
||||
class ClearButton;
|
||||
class SearchButton;
|
||||
class SearchLineEdit : public LineEdit
|
||||
class DLLEXPORT SearchLineEdit : public LineEdit
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
@ -174,7 +174,7 @@ TrackProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex& sourceParen
|
||||
if ( q->numResults() )
|
||||
r = q->results().first();
|
||||
|
||||
if ( !m_showOfflineResults && !r.isNull() && !r->collection()->source()->isOnline() )
|
||||
if ( !m_showOfflineResults && !r.isNull() && !r->isOnline() )
|
||||
return false;
|
||||
|
||||
if ( filterRegExp().isEmpty() )
|
||||
|
@ -42,6 +42,17 @@ Query::get( const QString& artist, const QString& track, const QString& album, c
|
||||
}
|
||||
|
||||
|
||||
query_ptr
|
||||
Query::get( const QString& query, const QID& qid )
|
||||
{
|
||||
query_ptr q = query_ptr( new Query( query, qid ) );
|
||||
|
||||
if ( !qid.isEmpty() )
|
||||
Pipeline::instance()->resolve( q );
|
||||
return q;
|
||||
}
|
||||
|
||||
|
||||
Query::Query( const QString& artist, const QString& track, const QString& album, const QID& qid )
|
||||
: m_solved( false )
|
||||
, m_playable( false )
|
||||
@ -51,6 +62,26 @@ Query::Query( const QString& artist, const QString& track, const QString& album,
|
||||
, m_album( album )
|
||||
, m_track( track )
|
||||
, m_duration( -1 )
|
||||
{
|
||||
if ( !qid.isEmpty() )
|
||||
{
|
||||
connect( Database::instance(), SIGNAL( indexReady() ), SLOT( refreshResults() ), Qt::QueuedConnection );
|
||||
}
|
||||
|
||||
connect( Pipeline::instance(), SIGNAL( resolverAdded( Resolver* ) ),
|
||||
SLOT( onResolverAdded() ), Qt::QueuedConnection );
|
||||
connect( Pipeline::instance(), SIGNAL( resolverRemoved( Resolver* ) ),
|
||||
SLOT( onResolverRemoved() ), Qt::QueuedConnection );
|
||||
}
|
||||
|
||||
|
||||
Query::Query( const QString& query, const QID& qid )
|
||||
: m_solved( false )
|
||||
, m_playable( false )
|
||||
, m_resolveFinished( false )
|
||||
, m_qid( qid )
|
||||
, m_fullTextQuery( query )
|
||||
, m_duration( -1 )
|
||||
{
|
||||
if ( !qid.isEmpty() )
|
||||
{
|
||||
@ -122,6 +153,26 @@ Query::onResolvingFinished()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Query::onResolverAdded()
|
||||
{
|
||||
if ( !solved() )
|
||||
{
|
||||
refreshResults();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Query::onResolverRemoved()
|
||||
{
|
||||
if ( !solved() )
|
||||
{
|
||||
refreshResults();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QList< result_ptr >
|
||||
Query::results() const
|
||||
{
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
@ -46,7 +46,10 @@ friend class ::DatabaseCommand_LoadPlaylistEntries;
|
||||
|
||||
public:
|
||||
static query_ptr get( const QString& artist, const QString& track, const QString& album, const QID& qid = QString() );
|
||||
static query_ptr get( const QString& query, const QID& qid );
|
||||
|
||||
explicit Query( const QString& artist, const QString& track, const QString& album, const QID& qid );
|
||||
explicit Query( const QString& query, const QID& qid );
|
||||
|
||||
/// returns list of all results so far
|
||||
QList< result_ptr > results() const;
|
||||
@ -64,8 +67,9 @@ public:
|
||||
/// true when any result has been found (score may be less than 1.0)
|
||||
bool playable() const { return m_playable; }
|
||||
|
||||
bool isFullTextQuery() const { return !m_fullTextQuery.isEmpty(); }
|
||||
bool resolvingFinished() const { return m_resolveFinished; }
|
||||
|
||||
|
||||
unsigned int lastPipelineWeight() const { return m_lastpipelineweight; }
|
||||
void setLastPipelineWeight( unsigned int w ) { m_lastpipelineweight = w; }
|
||||
|
||||
@ -75,7 +79,7 @@ public:
|
||||
void setResultHint( const QString& resultHint ) { m_resultHint = resultHint; }
|
||||
void setDuration( int duration ) { m_duration = duration; }
|
||||
void setResolveFinished( bool resolved ) { m_resolveFinished = resolved; }
|
||||
|
||||
|
||||
QVariant toVariant() const;
|
||||
QString toString() const;
|
||||
|
||||
@ -83,6 +87,7 @@ public:
|
||||
QString artist() const { return m_artist; }
|
||||
QString album() const { return m_album; }
|
||||
QString track() const { return m_track; }
|
||||
QString fullTextQuery() const { return m_fullTextQuery; }
|
||||
int duration() const { return m_duration; }
|
||||
|
||||
signals:
|
||||
@ -92,7 +97,7 @@ signals:
|
||||
void resultsChanged();
|
||||
void solvedStateChanged( bool state );
|
||||
void resolvingFinished( bool hasResults );
|
||||
|
||||
|
||||
public slots:
|
||||
/// (indirectly) called by resolver plugins when results are found
|
||||
void addResults( const QList< Tomahawk::result_ptr >& );
|
||||
@ -100,6 +105,10 @@ public slots:
|
||||
|
||||
void onResolvingFinished();
|
||||
|
||||
// resolve if not solved()
|
||||
void onResolverAdded();
|
||||
void onResolverRemoved();
|
||||
|
||||
private slots:
|
||||
void onResultStatusChanged();
|
||||
void refreshResults();
|
||||
@ -118,6 +127,8 @@ private:
|
||||
QString m_artist;
|
||||
QString m_album;
|
||||
QString m_track;
|
||||
QString m_fullTextQuery;
|
||||
|
||||
int m_duration;
|
||||
QString m_resultHint;
|
||||
|
||||
|
@ -283,6 +283,8 @@ void
|
||||
SipHandler::removeSipPlugin( SipPlugin* p )
|
||||
{
|
||||
p->disconnectPlugin();
|
||||
p->deletePlugin();
|
||||
|
||||
emit pluginRemoved( p );
|
||||
// emit first so sipmodel can find the indexOf
|
||||
|
||||
|
@ -111,3 +111,9 @@ SipPlugin::onPeerOffline(const QString& peerId)
|
||||
m_peersOnline.removeAll( peerId );
|
||||
}
|
||||
|
||||
void
|
||||
SipPlugin::deletePlugin()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
@ -91,6 +91,8 @@ public slots:
|
||||
|
||||
virtual void refreshProxy();
|
||||
|
||||
// so plugins can clean up after themselves
|
||||
virtual void deletePlugin();
|
||||
signals:
|
||||
void error( int, const QString& );
|
||||
void stateChanged( SipPlugin::ConnectionState state );
|
||||
|
@ -753,3 +753,16 @@ TomahawkSettings::setEnabledScriptResolvers( const QStringList& resolvers )
|
||||
{
|
||||
setValue( "script/loadedresolvers", resolvers );
|
||||
}
|
||||
|
||||
bool
|
||||
TomahawkSettings::nowPlayingEnabled() const
|
||||
{
|
||||
return value( "adium/enablenowplaying", false ).toBool();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TomahawkSettings::setNowPlayingEnabled( bool enable )
|
||||
{
|
||||
setValue( "adium/enablenowplaying", enable );
|
||||
}
|
||||
|
@ -175,6 +175,11 @@ public:
|
||||
QStringList enabledScriptResolvers() const;
|
||||
void setEnabledScriptResolvers( const QStringList& resolvers );
|
||||
|
||||
// Now-Playing Settings
|
||||
// For now, just Adium. Soon, the world!
|
||||
bool nowPlayingEnabled() const; // false by default
|
||||
void setNowPlayingEnabled( bool enable );
|
||||
|
||||
|
||||
signals:
|
||||
void changed();
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
@ -23,83 +23,25 @@
|
||||
|
||||
AnimatedSplitter::AnimatedSplitter( QWidget* parent )
|
||||
: QSplitter( parent )
|
||||
, m_animateIndex( -1 )
|
||||
, m_greedyIndex( 0 )
|
||||
{
|
||||
setHandleWidth( 1 );
|
||||
|
||||
m_timeLine = new QTimeLine( ANIMATION_TIME, this );
|
||||
m_timeLine->setUpdateInterval( 5 );
|
||||
m_timeLine->setEasingCurve( QEasingCurve::OutBack );
|
||||
|
||||
connect( m_timeLine, SIGNAL( frameChanged( int ) ), SLOT( onAnimationStep( int ) ) );
|
||||
connect( m_timeLine, SIGNAL( finished() ), SLOT( onAnimationFinished() ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AnimatedSplitter::show( int index, bool animate )
|
||||
{
|
||||
m_animateIndex = index;
|
||||
|
||||
QWidget* w = widget( index );
|
||||
QSize size = w->sizeHint();
|
||||
|
||||
if ( w->height() == size.height() )
|
||||
return;
|
||||
|
||||
emit shown( w );
|
||||
w->setMaximumHeight( QWIDGETSIZE_MAX );
|
||||
qDebug() << "animating to:" << size.height() << "from" << w->height();
|
||||
|
||||
m_animateForward = true;
|
||||
if ( animate )
|
||||
{
|
||||
if ( m_timeLine->state() == QTimeLine::Running )
|
||||
m_timeLine->stop();
|
||||
|
||||
m_timeLine->setFrameRange( w->height(), size.height() );
|
||||
m_timeLine->setDirection( QTimeLine::Forward );
|
||||
m_timeLine->start();
|
||||
}
|
||||
else
|
||||
{
|
||||
onAnimationStep( size.height() );
|
||||
onAnimationFinished();
|
||||
}
|
||||
emit shown( w, animate );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AnimatedSplitter::hide( int index, bool animate )
|
||||
{
|
||||
m_animateIndex = index;
|
||||
|
||||
QWidget* w = widget( index );
|
||||
int minHeight = m_sizes.at( index ).height();
|
||||
|
||||
if ( w->height() == minHeight )
|
||||
return;
|
||||
|
||||
emit hidden( w );
|
||||
w->setMinimumHeight( minHeight );
|
||||
// qDebug() << "animating to:" << w->height() << "from" << minHeight;
|
||||
|
||||
m_animateForward = false;
|
||||
if ( animate )
|
||||
{
|
||||
if ( m_timeLine->state() == QTimeLine::Running )
|
||||
m_timeLine->stop();
|
||||
|
||||
m_timeLine->setFrameRange( minHeight, w->height() );
|
||||
m_timeLine->setDirection( QTimeLine::Backward );
|
||||
m_timeLine->start();
|
||||
}
|
||||
else
|
||||
{
|
||||
onAnimationStep( minHeight );
|
||||
onAnimationFinished();
|
||||
}
|
||||
emit hidden( w, animate );
|
||||
}
|
||||
|
||||
|
||||
@ -107,7 +49,6 @@ void
|
||||
AnimatedSplitter::addWidget( QWidget* widget )
|
||||
{
|
||||
QSplitter::addWidget( widget );
|
||||
m_sizes << widget->minimumSize();
|
||||
}
|
||||
|
||||
|
||||
@ -116,13 +57,11 @@ AnimatedSplitter::addWidget( AnimatedWidget* widget )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << widget;
|
||||
QSplitter::addWidget( widget );
|
||||
m_sizes << widget->hiddenSize();
|
||||
|
||||
connect( widget, SIGNAL( showWidget() ), SLOT( onShowRequest() ) );
|
||||
connect( widget, SIGNAL( hideWidget() ), SLOT( onHideRequest() ) );
|
||||
connect( widget, SIGNAL( hiddenSizeChanged() ), SLOT( onHiddenSizeChanged() ) );
|
||||
connect( this, SIGNAL( shown( QWidget* ) ), widget, SLOT( onShown( QWidget* ) ) );
|
||||
connect( this, SIGNAL( hidden( QWidget* ) ), widget, SLOT( onHidden( QWidget* ) ) );
|
||||
connect( this, SIGNAL( shown( QWidget*, bool ) ), widget, SLOT( onShown( QWidget*, bool ) ) );
|
||||
connect( this, SIGNAL( hidden( QWidget*, bool ) ), widget, SLOT( onHidden( QWidget*, bool ) ) );
|
||||
}
|
||||
|
||||
|
||||
@ -131,18 +70,9 @@ AnimatedSplitter::onShowRequest()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << sender();
|
||||
|
||||
int j = -1;
|
||||
for ( int i = 0; i < count(); i ++ )
|
||||
{
|
||||
if ( widget( i ) == sender() )
|
||||
{
|
||||
j = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( j > 0 )
|
||||
show( j );
|
||||
AnimatedWidget* w = (AnimatedWidget*)(sender());
|
||||
if ( indexOf( w ) > 0 )
|
||||
show( indexOf( w ) );
|
||||
else
|
||||
qDebug() << "Could not find widget:" << sender();
|
||||
}
|
||||
@ -151,72 +81,16 @@ AnimatedSplitter::onShowRequest()
|
||||
void
|
||||
AnimatedSplitter::onHideRequest()
|
||||
{
|
||||
int j = -1;
|
||||
for ( int i = 0; i < count(); i ++ )
|
||||
{
|
||||
if ( widget( i ) == sender() )
|
||||
{
|
||||
j = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( j > 0 )
|
||||
hide( j );
|
||||
AnimatedWidget* w = (AnimatedWidget*)(sender());
|
||||
if ( indexOf( w ) > 0 )
|
||||
hide( indexOf( w ) );
|
||||
else
|
||||
qDebug() << "Could not find widget:" << sender();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AnimatedSplitter::onAnimationStep( int frame )
|
||||
{
|
||||
QList< int > sizes;
|
||||
|
||||
for ( int i = 0; i < count(); i ++ )
|
||||
{
|
||||
int j = 0;
|
||||
|
||||
if ( i == m_greedyIndex )
|
||||
{
|
||||
j = height() - frame; // FIXME
|
||||
}
|
||||
else if ( i == m_animateIndex )
|
||||
{
|
||||
j = frame;
|
||||
}
|
||||
else
|
||||
{
|
||||
j = widget( i )->height();
|
||||
}
|
||||
|
||||
sizes << j;
|
||||
}
|
||||
|
||||
setSizes( sizes );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AnimatedSplitter::onAnimationFinished()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
|
||||
QWidget* w = widget( m_animateIndex );
|
||||
if ( m_animateForward )
|
||||
{
|
||||
w->setMinimumHeight( w->minimumHeight() );
|
||||
}
|
||||
else
|
||||
{
|
||||
w->setMaximumHeight( m_sizes.at( m_animateIndex ).height() );
|
||||
}
|
||||
|
||||
m_animateIndex = -1;
|
||||
}
|
||||
|
||||
void
|
||||
AnimatedSplitter::setGreedyWidget(int index)
|
||||
AnimatedSplitter::setGreedyWidget( int index )
|
||||
{
|
||||
m_greedyIndex = index;
|
||||
if( !widget( index ) )
|
||||
@ -227,17 +101,7 @@ AnimatedSplitter::setGreedyWidget(int index)
|
||||
else
|
||||
policy.setVerticalStretch( 1 );
|
||||
widget( m_greedyIndex )->setSizePolicy( policy );
|
||||
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AnimatedSplitter::onHiddenSizeChanged()
|
||||
{
|
||||
AnimatedWidget* w = (AnimatedWidget*)(sender());
|
||||
int i = indexOf( w );
|
||||
|
||||
m_sizes.replace( i, w->hiddenSize() );
|
||||
}
|
||||
|
||||
|
||||
@ -246,24 +110,98 @@ AnimatedWidget::AnimatedWidget( AnimatedSplitter* parent )
|
||||
, m_isHidden( false )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
|
||||
m_timeLine = new QTimeLine( ANIMATION_TIME, this );
|
||||
m_timeLine->setUpdateInterval( 5 );
|
||||
m_timeLine->setEasingCurve( QEasingCurve::OutBack );
|
||||
|
||||
connect( m_timeLine, SIGNAL( frameChanged( int ) ), SLOT( onAnimationStep( int ) ) );
|
||||
connect( m_timeLine, SIGNAL( finished() ), SLOT( onAnimationFinished() ) );
|
||||
}
|
||||
|
||||
|
||||
AnimatedWidget::~AnimatedWidget()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AnimatedWidget::onShown( QWidget* )
|
||||
AnimatedWidget::onShown( QWidget* widget, bool animated )
|
||||
{
|
||||
if ( widget != this )
|
||||
return;
|
||||
|
||||
qDebug() << Q_FUNC_INFO << this;
|
||||
|
||||
m_animateForward = true;
|
||||
if ( animated )
|
||||
{
|
||||
if ( m_timeLine->state() == QTimeLine::Running )
|
||||
m_timeLine->stop();
|
||||
|
||||
m_timeLine->setFrameRange( height(), sizeHint().height() );
|
||||
m_timeLine->setDirection( QTimeLine::Forward );
|
||||
m_timeLine->start();
|
||||
}
|
||||
else
|
||||
{
|
||||
onAnimationStep( sizeHint().height() );
|
||||
onAnimationFinished();
|
||||
}
|
||||
|
||||
m_isHidden = false;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AnimatedWidget::onHidden( QWidget* )
|
||||
AnimatedWidget::onHidden( QWidget* widget, bool animated )
|
||||
{
|
||||
if ( widget != this )
|
||||
return;
|
||||
|
||||
qDebug() << Q_FUNC_INFO << this;
|
||||
|
||||
m_animateForward = false;
|
||||
int minHeight = hiddenSize().height();
|
||||
|
||||
if ( animated )
|
||||
{
|
||||
if ( m_timeLine->state() == QTimeLine::Running )
|
||||
m_timeLine->stop();
|
||||
|
||||
m_timeLine->setFrameRange( minHeight, height() );
|
||||
m_timeLine->setDirection( QTimeLine::Backward );
|
||||
m_timeLine->start();
|
||||
}
|
||||
else
|
||||
{
|
||||
onAnimationStep( minHeight );
|
||||
onAnimationFinished();
|
||||
}
|
||||
|
||||
m_isHidden = true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AnimatedWidget::onAnimationStep( int frame )
|
||||
{
|
||||
setFixedHeight( frame );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AnimatedWidget::onAnimationFinished()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
|
||||
if ( m_animateForward )
|
||||
{
|
||||
setMinimumHeight( hiddenSize().height() );
|
||||
setMaximumHeight( QWIDGETSIZE_MAX );
|
||||
}
|
||||
else
|
||||
{
|
||||
setFixedHeight( hiddenSize().height() );
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
@ -43,56 +43,52 @@ public:
|
||||
void addWidget( AnimatedWidget* widget );
|
||||
|
||||
signals:
|
||||
void shown( QWidget* );
|
||||
void hidden( QWidget* );
|
||||
void shown( QWidget*, bool animated );
|
||||
void hidden( QWidget*, bool animated );
|
||||
|
||||
private slots:
|
||||
void onShowRequest();
|
||||
void onHideRequest();
|
||||
|
||||
void onAnimationStep( int frame );
|
||||
void onAnimationFinished();
|
||||
|
||||
void onHiddenSizeChanged();
|
||||
|
||||
private:
|
||||
int m_animateIndex;
|
||||
bool m_animateForward;
|
||||
|
||||
int m_greedyIndex;
|
||||
QList<QSize> m_sizes;
|
||||
QTimeLine* m_timeLine;
|
||||
};
|
||||
|
||||
class DLLEXPORT AnimatedWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AnimatedWidget( AnimatedSplitter* parent = 0 );
|
||||
explicit AnimatedWidget( AnimatedSplitter* parent );
|
||||
virtual ~AnimatedWidget();
|
||||
|
||||
|
||||
QSize hiddenSize() const { return m_hiddenSize; }
|
||||
void setHiddenSize( const QSize& size ) { m_hiddenSize = size; emit hiddenSizeChanged(); }
|
||||
|
||||
bool isHidden() const { return m_isHidden; }
|
||||
|
||||
public slots:
|
||||
virtual void onShown( QWidget* );
|
||||
virtual void onHidden( QWidget* );
|
||||
virtual void onShown( QWidget*, bool animated );
|
||||
virtual void onHidden( QWidget*, bool animated );
|
||||
|
||||
signals:
|
||||
void showWidget();
|
||||
void hideWidget();
|
||||
|
||||
void hiddenSizeChanged();
|
||||
|
||||
private slots:
|
||||
void onAnimationStep( int frame );
|
||||
void onAnimationFinished();
|
||||
|
||||
protected:
|
||||
|
||||
AnimatedSplitter* splitter() { return m_parent; }
|
||||
|
||||
|
||||
private:
|
||||
AnimatedSplitter* m_parent;
|
||||
bool m_animateForward;
|
||||
QSize m_hiddenSize;
|
||||
bool m_isHidden;
|
||||
QTimeLine* m_timeLine;
|
||||
};
|
||||
|
||||
#endif //ANIMATEDSPLITTER_H
|
||||
|
@ -584,7 +584,7 @@ ViewManager::setPage( ViewPage* page, bool trackHistory )
|
||||
|
||||
// save the old playlist shuffle state in config before we change playlists
|
||||
saveCurrentPlaylistSettings();
|
||||
|
||||
|
||||
unlinkPlaylist();
|
||||
|
||||
if ( !m_pageHistory.contains( page ) )
|
||||
@ -630,6 +630,7 @@ ViewManager::setPage( ViewPage* page, bool trackHistory )
|
||||
updateView();
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ViewManager::isNewPlaylistPageVisible() const
|
||||
{
|
||||
@ -661,7 +662,7 @@ ViewManager::saveCurrentPlaylistSettings()
|
||||
{
|
||||
TomahawkSettings* s = TomahawkSettings::instance();
|
||||
Tomahawk::playlist_ptr pl = playlistForInterface( currentPlaylistInterface() );
|
||||
|
||||
|
||||
if ( !pl.isNull() ) {
|
||||
s->setShuffleState( pl->guid(), currentPlaylistInterface()->shuffled() );
|
||||
s->setRepeatMode( pl->guid(), currentPlaylistInterface()->repeatMode() );
|
||||
@ -726,7 +727,7 @@ ViewManager::updateView()
|
||||
m_infobar->setCaption( currentPage()->title() );
|
||||
m_infobar->setDescription( currentPage()->description() );
|
||||
m_infobar->setPixmap( currentPage()->pixmap() );
|
||||
|
||||
|
||||
// turn on shuffle/repeat mode for the new playlist view if specified in config
|
||||
loadCurrentPlaylistSettings();
|
||||
}
|
||||
@ -739,7 +740,7 @@ ViewManager::loadCurrentPlaylistSettings()
|
||||
if ( !pl.isNull() ) {
|
||||
currentPlaylistInterface()->setShuffled( s->shuffleState( pl->guid() ));
|
||||
currentPlaylistInterface()->setRepeatMode( s->repeatMode( pl->guid() ));
|
||||
} else {
|
||||
} else {
|
||||
Tomahawk::dynplaylist_ptr dynPl = dynamicPlaylistForInterface( currentPlaylistInterface() );
|
||||
if ( !dynPl.isNull() ) {
|
||||
currentPlaylistInterface()->setShuffled( s->shuffleState( dynPl->guid() ));
|
||||
|
@ -125,11 +125,9 @@ NewPlaylistWidget::suggestionsFound()
|
||||
m_suggestionsModel = new PlaylistModel( ui->suggestionsView );
|
||||
ui->suggestionsView->setPlaylistModel( m_suggestionsModel );
|
||||
|
||||
QList<Tomahawk::query_ptr> ql;
|
||||
foreach( const Tomahawk::query_ptr& query, m_queries )
|
||||
{
|
||||
m_suggestionsModel->append( query );
|
||||
ql.append( query );
|
||||
}
|
||||
|
||||
loader->deleteLater();
|
||||
|
104
src/libtomahawk/widgets/searchwidget.cpp
Normal file
104
src/libtomahawk/widgets/searchwidget.cpp
Normal file
@ -0,0 +1,104 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "searchwidget.h"
|
||||
#include "ui_searchwidget.h"
|
||||
|
||||
#include <QPushButton>
|
||||
#include <QDialogButtonBox>
|
||||
|
||||
#include "utils/tomahawkutils.h"
|
||||
|
||||
#include "viewmanager.h"
|
||||
#include "playlist/playlistmodel.h"
|
||||
|
||||
#include "widgets/overlaywidget.h"
|
||||
|
||||
#include "sourcelist.h"
|
||||
|
||||
|
||||
SearchWidget::SearchWidget( const QString& search, QWidget* parent )
|
||||
: QWidget( parent )
|
||||
, ui( new Ui::SearchWidget )
|
||||
, m_search( search )
|
||||
{
|
||||
ui->setupUi( this );
|
||||
|
||||
m_resultsModel = new PlaylistModel( ui->resultsView );
|
||||
ui->resultsView->setPlaylistModel( m_resultsModel );
|
||||
ui->resultsView->overlay()->setEnabled( false );
|
||||
|
||||
m_queries << Tomahawk::Query::get( search, uuid() );
|
||||
|
||||
foreach ( const Tomahawk::query_ptr& query, m_queries )
|
||||
{
|
||||
connect( query.data(), SIGNAL( resultsAdded( QList<Tomahawk::result_ptr> ) ), SLOT( onResultsFound( QList<Tomahawk::result_ptr> ) ) );
|
||||
}
|
||||
|
||||
connect( ui->buttonBox, SIGNAL( rejected() ), SLOT( cancel() ) );
|
||||
}
|
||||
|
||||
|
||||
SearchWidget::~SearchWidget()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SearchWidget::changeEvent( QEvent* e )
|
||||
{
|
||||
QWidget::changeEvent( e );
|
||||
switch ( e->type() )
|
||||
{
|
||||
case QEvent::LanguageChange:
|
||||
ui->retranslateUi( this );
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SearchWidget::onResultsFound( const QList<Tomahawk::result_ptr>& results )
|
||||
{
|
||||
foreach( const Tomahawk::result_ptr& result, results )
|
||||
{
|
||||
if ( !result->collection().isNull() && !result->isOnline() )
|
||||
continue;
|
||||
|
||||
QList< Tomahawk::result_ptr > rl;
|
||||
rl << result;
|
||||
|
||||
Tomahawk::query_ptr q = result->toQuery();
|
||||
q->addResults( rl );
|
||||
qDebug() << result->toString();
|
||||
|
||||
m_resultsModel->append( q );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SearchWidget::cancel()
|
||||
{
|
||||
emit destroyed( this );
|
||||
deleteLater();
|
||||
}
|
77
src/libtomahawk/widgets/searchwidget.h
Normal file
77
src/libtomahawk/widgets/searchwidget.h
Normal file
@ -0,0 +1,77 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SEARCHWIDGET_H
|
||||
#define SEARCHWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QTimer>
|
||||
|
||||
#include "result.h"
|
||||
#include "playlistinterface.h"
|
||||
#include "viewpage.h"
|
||||
|
||||
#include "dllmacro.h"
|
||||
|
||||
class QPushButton;
|
||||
class PlaylistModel;
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class SearchWidget;
|
||||
}
|
||||
|
||||
class DLLEXPORT SearchWidget : public QWidget, public Tomahawk::ViewPage
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SearchWidget( const QString& search, QWidget* parent = 0 );
|
||||
~SearchWidget();
|
||||
|
||||
virtual QWidget* widget() { return this; }
|
||||
virtual PlaylistInterface* playlistInterface() const { return 0; }
|
||||
|
||||
virtual QString title() const { return tr( "Search" ); }
|
||||
virtual QString description() const { return tr( "Results for '%1'" ).arg( m_search ); }
|
||||
|
||||
virtual bool showStatsBar() const { return false; }
|
||||
|
||||
virtual bool jumpToCurrentTrack() { return false; }
|
||||
|
||||
protected:
|
||||
void changeEvent( QEvent* e );
|
||||
|
||||
signals:
|
||||
void destroyed( QWidget* widget );
|
||||
|
||||
private slots:
|
||||
void onResultsFound( const QList<Tomahawk::result_ptr>& results );
|
||||
|
||||
void cancel();
|
||||
|
||||
private:
|
||||
Ui::SearchWidget *ui;
|
||||
|
||||
QString m_search;
|
||||
|
||||
PlaylistModel* m_resultsModel;
|
||||
QList< Tomahawk::query_ptr > m_queries;
|
||||
};
|
||||
|
||||
#endif // NEWPLAYLISTWIDGET_H
|
38
src/libtomahawk/widgets/searchwidget.ui
Normal file
38
src/libtomahawk/widgets/searchwidget.ui
Normal file
@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>SearchWidget</class>
|
||||
<widget class="QWidget" name="SearchWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>985</width>
|
||||
<height>460</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::TabFocus</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="PlaylistView" name="resultsView"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>PlaylistView</class>
|
||||
<extends>QTreeView</extends>
|
||||
<header>playlist/playlistview.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
40
src/mac/macdelegate.h
Normal file
40
src/mac/macdelegate.h
Normal file
@ -0,0 +1,40 @@
|
||||
#ifndef MACDELEGATE_H
|
||||
#define MACDELEGATE_H
|
||||
|
||||
// This file inspired by clementine's macdelegate.h
|
||||
|
||||
#import <AppKit/NSApplication.h>
|
||||
|
||||
#include "SPMediaKeyTap.h"
|
||||
|
||||
namespace Tomahawk {
|
||||
class MacShortcutHandler;
|
||||
class PlatformInterface;
|
||||
}
|
||||
|
||||
#ifdef SNOW_LEOPARD
|
||||
@interface AppDelegate :NSObject <NSApplicationDelegate> {
|
||||
#else
|
||||
@interface AppDelegate :NSObject {
|
||||
#endif
|
||||
Tomahawk::PlatformInterface* application_handler_;
|
||||
NSMenu* dock_menu_;
|
||||
SPMediaKeyTap* key_tap_;
|
||||
Tomahawk::MacShortcutHandler* shortcut_handler_;
|
||||
}
|
||||
|
||||
- (id) initWithHandler: (Tomahawk::PlatformInterface*)handler;
|
||||
// NSApplicationDelegate
|
||||
- (BOOL) applicationShouldHandleReopen: (NSApplication*)app hasVisibleWindows:(BOOL)flag;
|
||||
- (NSMenu*) applicationDockMenu: (NSApplication*)sender;
|
||||
- (void) setDockMenu: (NSMenu*)menu;
|
||||
- (Tomahawk::MacShortcutHandler*) shortcutHandler;
|
||||
- (void) setShortcutHandler: (Tomahawk::MacShortcutHandler*)backend;
|
||||
- (void)applicationDidFinishLaunching:(NSNotification*)aNotification;
|
||||
- (NSApplicationTerminateReply) applicationShouldTerminate:(NSApplication*)sender;
|
||||
- (void) mediaKeyTap: (SPMediaKeyTap*)keyTap receivedMediaKeyEvent:(NSEvent*)event;
|
||||
@end
|
||||
|
||||
|
||||
|
||||
#endif // MACDELEGATE_H
|
@ -17,7 +17,7 @@
|
||||
*/
|
||||
|
||||
#include "tomahawkapp_mac.h"
|
||||
#include "tomahawkapp_macdelegate.h"
|
||||
#include "macdelegate.h"
|
||||
#include "macshortcuthandler.h"
|
||||
#include <QDebug>
|
||||
|
||||
@ -42,6 +42,7 @@
|
||||
// See: http://www.rogueamoeba.com/utm/2007/09/29/apple-keyboard-media-key-event-handling/
|
||||
|
||||
@interface MacApplication :NSApplication {
|
||||
AppDelegate* delegate_;
|
||||
Tomahawk::MacShortcutHandler* shortcut_handler_;
|
||||
Tomahawk::PlatformInterface* application_handler_;
|
||||
}
|
||||
@ -51,7 +52,6 @@
|
||||
|
||||
- (Tomahawk::PlatformInterface*) application_handler;
|
||||
- (void) setApplicationHandler: (Tomahawk::PlatformInterface*)handler;
|
||||
- (void) mediaKeyEvent: (int)key state: (BOOL)state repeat: (BOOL)repeat;
|
||||
@end
|
||||
|
||||
|
||||
@ -59,14 +59,22 @@
|
||||
|
||||
- (id) init {
|
||||
if ((self = [super init])) {
|
||||
application_handler_ = nil;
|
||||
// dock_menu_ = nil;
|
||||
application_handler_ = nil;
|
||||
shortcut_handler_ = nil;
|
||||
//dock_menu_ = nil;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id) initWithHandler: (Tomahawk::PlatformInterface*)handler {
|
||||
application_handler_ = handler;
|
||||
|
||||
// Register defaults for the whitelist of apps that want to use media keys
|
||||
[[NSUserDefaults standardUserDefaults] registerDefaults:[NSDictionary dictionaryWithObjectsAndKeys:
|
||||
[SPMediaKeyTap defaultMediaKeyUserBundleIdentifiers], @"SPApplicationsNeedingMediaKeys",
|
||||
nil]];
|
||||
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@ -76,7 +84,7 @@
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
/*
|
||||
|
||||
- (void) setDockMenu: (NSMenu*)menu {
|
||||
dock_menu_ = menu;
|
||||
}
|
||||
@ -84,7 +92,45 @@
|
||||
- (NSMenu*) applicationDockMenu: (NSApplication*)sender {
|
||||
return dock_menu_;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
- (Tomahawk::MacShortcutHandler*) shortcutHandler {
|
||||
return shortcut_handler_;
|
||||
}
|
||||
|
||||
- (void) setShortcutHandler: (Tomahawk::MacShortcutHandler*)handler {
|
||||
qDebug() << "Setting shortcut handler of MacApp";
|
||||
// should be the same as MacApplication's
|
||||
shortcut_handler_ = handler;
|
||||
}
|
||||
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
|
||||
key_tap_ = [[SPMediaKeyTap alloc] initWithDelegate:self];
|
||||
if([SPMediaKeyTap usesGlobalMediaKeyTap])
|
||||
[key_tap_ startWatchingMediaKeys];
|
||||
else
|
||||
qWarning()<<"Media key monitoring disabled";
|
||||
|
||||
}
|
||||
|
||||
- (void) mediaKeyTap: (SPMediaKeyTap*)keyTap receivedMediaKeyEvent:(NSEvent*)event {
|
||||
NSAssert([event type] == NSSystemDefined && [event subtype] == SPSystemDefinedEventMediaKeys, @"Unexpected NSEvent in mediaKeyTap:receivedMediaKeyEvent:");
|
||||
|
||||
int key_code = (([event data1] & 0xFFFF0000) >> 16);
|
||||
int key_flags = ([event data1] & 0x0000FFFF);
|
||||
BOOL key_is_pressed = (((key_flags & 0xFF00) >> 8)) == 0xA;
|
||||
// not used. keep just in case
|
||||
// int key_repeat = (key_flags & 0x1);
|
||||
|
||||
if (!shortcut_handler_) {
|
||||
qWarning() << "No shortcut handler when we get a media key event...";
|
||||
return;
|
||||
}
|
||||
if (key_is_pressed) {
|
||||
shortcut_handler_->macMediaKeyPressed(key_code);
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL) application: (NSApplication*)app openFile:(NSString*)filename {
|
||||
qDebug() << "Wants to open:" << [filename UTF8String];
|
||||
|
||||
@ -94,6 +140,11 @@
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (NSApplicationTerminateReply) applicationShouldTerminate:(NSApplication*) sender {
|
||||
return NSTerminateNow;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation MacApplication
|
||||
@ -127,7 +178,7 @@
|
||||
}
|
||||
|
||||
- (void) setShortcutHandler: (Tomahawk::MacShortcutHandler*)handler {
|
||||
qDebug() << "Setting shortcut handler of MacAPp";
|
||||
// should be the same as AppDelegate's
|
||||
shortcut_handler_ = handler;
|
||||
}
|
||||
|
||||
@ -136,30 +187,22 @@
|
||||
}
|
||||
|
||||
- (void) setApplicationHandler: (Tomahawk::PlatformInterface*)handler {
|
||||
AppDelegate* delegate = [[AppDelegate alloc] initWithHandler:handler];
|
||||
[self setDelegate:delegate];
|
||||
delegate_ = [[AppDelegate alloc] initWithHandler:handler];
|
||||
// App-shortcut-handler set before delegate is set.
|
||||
// this makes sure the delegate's shortcut_handler is set
|
||||
[delegate_ setShortcutHandler:shortcut_handler_];
|
||||
[self setDelegate:delegate_];
|
||||
}
|
||||
|
||||
-(void) sendEvent: (NSEvent*)event {
|
||||
if ([event type] == NSSystemDefined && [event subtype] == 8) {
|
||||
int keycode = (([event data1] & 0xFFFF0000) >> 16);
|
||||
int keyflags = ([event data1] & 0x0000FFFF);
|
||||
int keystate = (((keyflags & 0xFF00) >> 8)) == 0xA;
|
||||
int keyrepeat = (keyflags & 0x1);
|
||||
// If event tap is not installed, handle events that reach the app instead
|
||||
BOOL shouldHandleMediaKeyEventLocally = ![SPMediaKeyTap usesGlobalMediaKeyTap];
|
||||
|
||||
[self mediaKeyEvent: keycode state: keystate repeat: keyrepeat];
|
||||
}
|
||||
if(shouldHandleMediaKeyEventLocally && [event type] == NSSystemDefined && [event subtype] == SPSystemDefinedEventMediaKeys) {
|
||||
[(id)[self delegate] mediaKeyTap: nil receivedMediaKeyEvent: event];
|
||||
}
|
||||
|
||||
[super sendEvent: event];
|
||||
}
|
||||
|
||||
-(void) mediaKeyEvent: (int)key state: (BOOL)state repeat: (BOOL)repeat {
|
||||
if (!shortcut_handler_) {
|
||||
return;
|
||||
}
|
||||
if (state == 0) {
|
||||
shortcut_handler_->macMediaKeyPressed(key);
|
||||
}
|
||||
[super sendEvent: event];
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -75,11 +75,24 @@ QtScriptResolver::resolve( const Tomahawk::query_ptr& query )
|
||||
}
|
||||
|
||||
// qDebug() << Q_FUNC_INFO << query->toString();
|
||||
QString eval = QString( "resolve( '%1', '%2', '%3', '%4' );" )
|
||||
.arg( query->id().replace( "'", "\\'" ) )
|
||||
.arg( query->artist().replace( "'", "\\'" ) )
|
||||
.arg( query->album().replace( "'", "\\'" ) )
|
||||
.arg( query->track().replace( "'", "\\'" ) );
|
||||
QString eval;
|
||||
|
||||
if ( !query->isFullTextQuery() )
|
||||
{
|
||||
eval = QString( "resolve( '%1', '%2', '%3', '%4' );" )
|
||||
.arg( query->id().replace( "'", "\\'" ) )
|
||||
.arg( query->artist().replace( "'", "\\'" ) )
|
||||
.arg( query->album().replace( "'", "\\'" ) )
|
||||
.arg( query->track().replace( "'", "\\'" ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
eval = QString( "resolve( '%1', '%2', '%3', '%4' );" )
|
||||
.arg( query->id().replace( "'", "\\'" ) )
|
||||
.arg( query->fullTextQuery().replace( "'", "\\'" ) )
|
||||
.arg( QString() )
|
||||
.arg( QString() );
|
||||
}
|
||||
|
||||
QList< Tomahawk::result_ptr > results;
|
||||
|
||||
|
@ -208,12 +208,22 @@ ScriptResolver::resolve( const Tomahawk::query_ptr& query )
|
||||
{
|
||||
QVariantMap m;
|
||||
m.insert( "_msgtype", "rq" );
|
||||
m.insert( "artist", query->artist() );
|
||||
m.insert( "track", query->track() );
|
||||
m.insert( "qid", query->id() );
|
||||
|
||||
if ( query->isFullTextQuery() )
|
||||
{
|
||||
m.insert( "fulltext", query->fullTextQuery() );
|
||||
m.insert( "artist", query->artist() );
|
||||
m.insert( "track", query->fullTextQuery() );
|
||||
m.insert( "qid", query->id() );
|
||||
}
|
||||
else
|
||||
{
|
||||
m.insert( "artist", query->artist() );
|
||||
m.insert( "track", query->track() );
|
||||
m.insert( "qid", query->id() );
|
||||
}
|
||||
|
||||
const QByteArray msg = m_serializer.serialize( QVariant( m ) );
|
||||
// qDebug() << "ASKING SCRIPT RESOLVER TO RESOLVE:" << msg;
|
||||
sendMsg( msg );
|
||||
}
|
||||
|
||||
|
57
src/searchbox.ui
Normal file
57
src/searchbox.ui
Normal file
@ -0,0 +1,57 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>GlobalSearchWidget</class>
|
||||
<widget class="QWidget" name="GlobalSearchWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>345</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>141</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="SearchLineEdit" name="searchEdit">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>60</width>
|
||||
<height>27</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>180</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>SearchLineEdit</class>
|
||||
<extends>QLineEdit</extends>
|
||||
<header>libtomahawk/playlist/topbar/searchlineedit.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
@ -135,6 +135,13 @@ SettingsDialog::SettingsDialog( QWidget *parent )
|
||||
ui->scannerDirModeButton->setChecked( true );
|
||||
}
|
||||
|
||||
// NOW PLAYING
|
||||
#ifdef Q_WS_MAC
|
||||
ui->checkBoxEnableAdium->setChecked( s->nowPlayingEnabled() );
|
||||
#else
|
||||
ui->checkBoxEnableAdium->hide();
|
||||
#endif
|
||||
|
||||
// LAST FM
|
||||
ui->checkBoxEnableLastfm->setChecked( s->scrobblingEnabled() );
|
||||
ui->lineEditLastfmUsername->setText( s->lastFmUsername() );
|
||||
@ -182,6 +189,8 @@ SettingsDialog::~SettingsDialog()
|
||||
s->setScannerTime( ui->scannerTimeSpinBox->value() );
|
||||
s->setScannerMode( ui->scannerFileModeButton->isChecked() ? TomahawkSettings::Files : TomahawkSettings::Dirs );
|
||||
|
||||
s->setNowPlayingEnabled( ui->checkBoxEnableAdium->isChecked() );
|
||||
|
||||
s->setScrobblingEnabled( ui->checkBoxEnableLastfm->isChecked() );
|
||||
s->setLastFmUsername( ui->lineEditLastfmUsername->text() );
|
||||
s->setLastFmPassword( ui->lineEditLastfmPassword->text() );
|
||||
@ -432,7 +441,7 @@ SettingsDialog::onLastFmFinished()
|
||||
ui->pushButtonTestLastfmLogin->setText( tr( "Failed" ) );
|
||||
ui->pushButtonTestLastfmLogin->setEnabled( true );
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
qDebug() << "Couldn't get last.fm auth result";
|
||||
ui->pushButtonTestLastfmLogin->setText( tr( "Could not contact server" ) );
|
||||
@ -578,6 +587,15 @@ SettingsDialog::sipFactoryClicked( SipPluginFactory* factory )
|
||||
SipPlugin* p = factory->createPlugin();
|
||||
bool added = false;
|
||||
if( p->configWidget() ) {
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
// on osx a sheet needs to be non-modal
|
||||
DelegateConfigWrapper* dialog = new DelegateConfigWrapper( p->configWidget(), QString("%1 Config" ).arg( p->friendlyName() ), this, Qt::Sheet );
|
||||
dialog->setProperty( "sipplugin", QVariant::fromValue< QObject* >( p ) );
|
||||
connect( dialog, SIGNAL( finished( int ) ), this, SLOT( sipCreateConfigClosed( int ) ) );
|
||||
|
||||
dialog->show();
|
||||
#else
|
||||
DelegateConfigWrapper dialog( p->configWidget(), QString("%1 Config" ).arg( p->friendlyName() ), this );
|
||||
QWeakPointer< DelegateConfigWrapper > watcher( &dialog );
|
||||
int ret = dialog.exec();
|
||||
@ -594,13 +612,44 @@ SettingsDialog::sipFactoryClicked( SipPluginFactory* factory )
|
||||
// canceled, delete it
|
||||
added = false;
|
||||
}
|
||||
|
||||
handleSipPluginAdded( p, added );
|
||||
#endif
|
||||
} else {
|
||||
// no config, so just add it
|
||||
added = true;
|
||||
TomahawkSettings::instance()->addSipPlugin( p->pluginId() );
|
||||
SipHandler::instance()->addSipPlugin( p );
|
||||
|
||||
handleSipPluginAdded( p, added );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
SettingsDialog::sipCreateConfigClosed( int finished )
|
||||
{
|
||||
DelegateConfigWrapper* dialog = qobject_cast< DelegateConfigWrapper* >( sender() );
|
||||
SipPlugin* p = qobject_cast< SipPlugin* >( dialog->property( "sipplugin" ).value< QObject* >() );
|
||||
Q_ASSERT( p );
|
||||
|
||||
bool added = false;
|
||||
if( finished == QDialog::Accepted ) {
|
||||
|
||||
p->saveConfig();
|
||||
TomahawkSettings::instance()->addSipPlugin( p->pluginId() );
|
||||
SipHandler::instance()->addSipPlugin( p );
|
||||
|
||||
added = true;
|
||||
}
|
||||
|
||||
handleSipPluginAdded( p, added );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SettingsDialog::handleSipPluginAdded( SipPlugin* p, bool added )
|
||||
{
|
||||
SipPluginFactory* f = SipHandler::instance()->factoryFromPlugin( p );
|
||||
if( added && f && f->isUnique() ) {
|
||||
// remove from actions list
|
||||
@ -620,6 +669,7 @@ SettingsDialog::sipFactoryClicked( SipPluginFactory* factory )
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SettingsDialog::sipContextMenuRequest( const QPoint& p )
|
||||
{
|
||||
@ -675,9 +725,9 @@ ProxyDialog::ProxyDialog( QWidget *parent )
|
||||
, ui( new Ui::ProxyDialog )
|
||||
{
|
||||
ui->setupUi( this );
|
||||
|
||||
|
||||
// ugly, I know, but...
|
||||
|
||||
|
||||
int i = 0;
|
||||
ui->typeBox->insertItem( i, "No Proxy", QNetworkProxy::NoProxy );
|
||||
m_forwardMap[ QNetworkProxy::NoProxy ] = i;
|
||||
@ -687,9 +737,9 @@ ProxyDialog::ProxyDialog( QWidget *parent )
|
||||
m_forwardMap[ QNetworkProxy::Socks5Proxy ] = i;
|
||||
m_backwardMap[ i ] = QNetworkProxy::Socks5Proxy;
|
||||
i++;
|
||||
|
||||
|
||||
TomahawkSettings* s = TomahawkSettings::instance();
|
||||
|
||||
|
||||
ui->typeBox->setCurrentIndex( m_forwardMap[s->proxyType()] );
|
||||
ui->hostLineEdit->setText( s->proxyHost() );
|
||||
ui->portSpinBox->setValue( s->proxyPort() );
|
||||
@ -731,18 +781,18 @@ ProxyDialog::proxyTypeChangedSlot( int index )
|
||||
ui->passwordLineEdit->setEnabled( true );
|
||||
ui->checkBoxUseProxyForDns->setEnabled( true );
|
||||
ui->noHostLineEdit->setEnabled( true );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ProxyDialog::saveSettings()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
|
||||
|
||||
//First set settings
|
||||
TomahawkSettings* s = TomahawkSettings::instance();
|
||||
s->setProxyHost( ui->hostLineEdit->text() );
|
||||
|
||||
|
||||
int port = ui->portSpinBox->value();
|
||||
s->setProxyPort( port );
|
||||
s->setProxyNoProxyHosts( ui->noHostLineEdit->text() );
|
||||
@ -750,10 +800,10 @@ ProxyDialog::saveSettings()
|
||||
s->setProxyPassword( ui->passwordLineEdit->text() );
|
||||
s->setProxyType( ui->typeBox->itemData( ui->typeBox->currentIndex() ).toInt() );
|
||||
s->setProxyDns( ui->checkBoxUseProxyForDns->checkState() == Qt::Checked );
|
||||
|
||||
|
||||
if( s->proxyHost().isEmpty() )
|
||||
return;
|
||||
|
||||
|
||||
TomahawkUtils::NetworkProxyFactory* proxyFactory = new TomahawkUtils::NetworkProxyFactory();
|
||||
QNetworkProxy proxy( static_cast<QNetworkProxy::ProxyType>(s->proxyType()), s->proxyHost(), s->proxyPort(), s->proxyUsername(), s->proxyPassword() );
|
||||
proxyFactory->setProxy( proxy );
|
||||
|
@ -48,7 +48,7 @@ public:
|
||||
|
||||
private slots:
|
||||
void proxyTypeChangedSlot( int index );
|
||||
|
||||
|
||||
private:
|
||||
Ui::ProxyDialog* ui;
|
||||
QHash<int,int> m_forwardMap;
|
||||
@ -97,12 +97,14 @@ private slots:
|
||||
// dialog slots
|
||||
void resolverConfigClosed( int value );
|
||||
void sipConfigClosed( int value );
|
||||
void sipCreateConfigClosed( int value );
|
||||
|
||||
void changePage( QListWidgetItem*, QListWidgetItem* );
|
||||
|
||||
private:
|
||||
void createIcons();
|
||||
void setupSipButtons();
|
||||
void handleSipPluginAdded( SipPlugin* p, bool added );
|
||||
|
||||
Ui_StackedSettingsDialog* ui;
|
||||
|
||||
|
@ -1,740 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>SettingsDialog</class>
|
||||
<widget class="QDialog" name="SettingsDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>621</width>
|
||||
<height>434</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>353</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Music Player Settings</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<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>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="margin">
|
||||
<number>16</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<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_2">
|
||||
<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>
|
||||
<spacer name="verticalSpacer_6">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>8</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</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_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>
|
||||
<widget class="QWidget" name="tabNetwork">
|
||||
<attribute name="title">
|
||||
<string>Network</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_11">
|
||||
<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">
|
||||
<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="checkBoxJabberAutoConnect">
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::RightToLeft</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Connect automatically when Tomahawk starts</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 class="QWidget" name="tabMusic">
|
||||
<attribute name="title">
|
||||
<string>Local Music</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<property name="margin">
|
||||
<number>16</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<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">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineEditMusicPath"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="buttonBrowse">
|
||||
<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>
|
||||
</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>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<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>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tabLastfm">
|
||||
<attribute name="title">
|
||||
<string>Last.fm</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
<property name="margin">
|
||||
<number>16</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBoxEnableLastfm">
|
||||
<property name="text">
|
||||
<string>Scrobble tracks to Last.fm</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Last.fm Login</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<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>
|
||||
<widget class="QPushButton" name="pushButtonTestLastfmLogin">
|
||||
<property name="text">
|
||||
<string>Test Login</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>221</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tabScriptResolvers">
|
||||
<attribute name="title">
|
||||
<string>Script Resolvers</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_8">
|
||||
<item>
|
||||
<widget class="QLabel" name="scriptLabel">
|
||||
<property name="text">
|
||||
<string>Loaded script resolvers:</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_7">
|
||||
<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>
|
||||
</widget>
|
||||
</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>SettingsDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>402</x>
|
||||
<y>348</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>SettingsDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>470</x>
|
||||
<y>348</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
@ -6,6 +6,7 @@
|
||||
#include <jreen/vcard.h>
|
||||
#include <jreen/vcardupdate.h>
|
||||
#include <jreen/presence.h>
|
||||
#include <jreen/iqreply.h>
|
||||
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
@ -20,8 +21,8 @@ AvatarManager::AvatarManager(Jreen::Client *client) :
|
||||
m_cachedAvatars = m_cacheDir.entryList();
|
||||
|
||||
connect(m_client, SIGNAL(serverFeaturesReceived(QSet<QString>)), SLOT(onNewConnection()));
|
||||
connect(m_client, SIGNAL(newPresence(Jreen::Presence)), SLOT(onNewPresence(Jreen::Presence)));
|
||||
connect(m_client, SIGNAL(newIQ(Jreen::IQ)), SLOT(onNewIq(Jreen::IQ)));
|
||||
connect(m_client, SIGNAL(presenceReceived(Jreen::Presence)), SLOT(onNewPresence(Jreen::Presence)));
|
||||
connect(m_client, SIGNAL(iqReceived(Jreen::IQ)), SLOT(onNewIq(Jreen::IQ)));
|
||||
|
||||
connect(this, SIGNAL(newAvatar(QString)), SLOT(onNewAvatar(QString)));
|
||||
}
|
||||
@ -42,12 +43,13 @@ void AvatarManager::fetchVCard(const QString &jid)
|
||||
|
||||
Jreen::IQ iq(Jreen::IQ::Get, jid );
|
||||
iq.addExtension(new Jreen::VCard());
|
||||
m_client->send( iq, this, SLOT( onNewIq( Jreen::IQ, int ) ), 0 );
|
||||
Jreen::IQReply *reply = m_client->send(iq);
|
||||
connect(reply, SIGNAL(received(Jreen::IQ)), SLOT(onNewIq(Jreen::IQ)));
|
||||
}
|
||||
|
||||
void AvatarManager::onNewPresence(const Jreen::Presence& presence)
|
||||
{
|
||||
Jreen::VCardUpdate::Ptr update = presence.findExtension<Jreen::VCardUpdate>();
|
||||
Jreen::VCardUpdate::Ptr update = presence.payload<Jreen::VCardUpdate>();
|
||||
if(update)
|
||||
{
|
||||
// qDebug() << "vcard: found update for" << presence.from().full();
|
||||
@ -74,9 +76,9 @@ void AvatarManager::onNewPresence(const Jreen::Presence& presence)
|
||||
}
|
||||
}
|
||||
|
||||
void AvatarManager::onNewIq(const Jreen::IQ& iq, int context)
|
||||
void AvatarManager::onNewIq(const Jreen::IQ& iq)
|
||||
{
|
||||
Jreen::VCard *vcard = iq.findExtension<Jreen::VCard>().data();
|
||||
Jreen::VCard::Ptr vcard = iq.payload<Jreen::VCard>();
|
||||
if(vcard)
|
||||
{
|
||||
iq.accept();
|
||||
@ -119,7 +121,7 @@ void AvatarManager::onNewIq(const Jreen::IQ& iq, int context)
|
||||
// qDebug() << Q_FUNC_INFO << "got own vcard";
|
||||
|
||||
Jreen::Presence presence = m_client->presence();
|
||||
Jreen::VCardUpdate::Ptr update = presence.findExtension<Jreen::VCardUpdate>();
|
||||
Jreen::VCardUpdate::Ptr update = presence.payload<Jreen::VCardUpdate>();
|
||||
if (update->photoHash() != avatarHash)
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << "Updating own presence...";
|
||||
|
@ -23,7 +23,7 @@ signals:
|
||||
|
||||
private slots:
|
||||
void onNewPresence( const Jreen::Presence& presence );
|
||||
void onNewIq(const Jreen::IQ &iq, int context = 0 );
|
||||
void onNewIq(const Jreen::IQ &iq);
|
||||
void onNewConnection();
|
||||
void onNewAvatar( const QString &jid );
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <QtPlugin>
|
||||
|
||||
#include "ui_configwidget.h"
|
||||
#include <QInputDialog>
|
||||
|
||||
SipPlugin*
|
||||
GoogleWrapperFactory::createPlugin( const QString& pluginId )
|
||||
@ -52,6 +53,26 @@ GoogleWrapper::icon() const
|
||||
return QIcon( ":/gmail-logo.png" );
|
||||
}
|
||||
|
||||
QString
|
||||
GoogleWrapper::defaultSuffix() const
|
||||
{
|
||||
return "@gmail.com";
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GoogleWrapper::showAddFriendDialog()
|
||||
{
|
||||
bool ok;
|
||||
QString id = QInputDialog::getText( 0, tr( "Add Friend" ),
|
||||
tr( "Enter Google Address:" ), QLineEdit::Normal,
|
||||
"", &ok );
|
||||
if ( !ok )
|
||||
return;
|
||||
|
||||
qDebug() << "Attempting to add google contact to roster:" << id;
|
||||
addContact( id );
|
||||
}
|
||||
|
||||
#ifdef GOOGLE_WRAPPER
|
||||
Q_EXPORT_PLUGIN2( sipfactory, GoogleWrapperFactory )
|
||||
|
@ -47,6 +47,11 @@ public:
|
||||
virtual const QString friendlyName() const { return "Google"; }
|
||||
virtual QIcon icon() const;
|
||||
|
||||
protected:
|
||||
QString defaultSuffix() const;
|
||||
|
||||
public slots:
|
||||
void showAddFriendDialog();
|
||||
};
|
||||
|
||||
#endif // GOOGLEWRAPPER_H
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include <jreen/directconnection.h>
|
||||
#include <jreen/tcpconnection.h>
|
||||
#include <jreen/softwareversion.h>
|
||||
#include <jreen/iqreply.h>
|
||||
|
||||
#include <qjson/parser.h>
|
||||
#include <qjson/serializer.h>
|
||||
@ -91,7 +92,7 @@ JabberPlugin::JabberPlugin( const QString& pluginId )
|
||||
m_client = new Jreen::Client( jid, m_currentPassword );
|
||||
setupClientHelper();
|
||||
|
||||
m_client->registerStanzaExtension(new TomahawkSipMessageFactory);
|
||||
m_client->registerPayload(new TomahawkSipMessageFactory);
|
||||
m_currentResource = QString::fromAscii( "tomahawk%1" ).arg( QString::number( qrand() % 10000 ) );
|
||||
m_client->setResource( m_currentResource );
|
||||
|
||||
@ -117,7 +118,7 @@ JabberPlugin::JabberPlugin( const QString& pluginId )
|
||||
m_client->disco()->addFeature( TOMAHAWK_FEATURE );
|
||||
|
||||
// setup caps node, legacy peer detection - used before 0.1
|
||||
Jreen::Capabilities::Ptr caps = m_client->presence().findExtension<Jreen::Capabilities>();
|
||||
Jreen::Capabilities::Ptr caps = m_client->presence().payload<Jreen::Capabilities>();
|
||||
caps->setNode( TOMAHAWK_CAP_NODE_NAME );
|
||||
//FIXME: caps->setVersion( TOMAHAWK_VERSION );
|
||||
|
||||
@ -129,9 +130,9 @@ JabberPlugin::JabberPlugin( const QString& pluginId )
|
||||
// setup slots
|
||||
connect(m_client, SIGNAL(serverFeaturesReceived(QSet<QString>)), SLOT(onConnect()));
|
||||
connect(m_client, SIGNAL(disconnected(Jreen::Client::DisconnectReason)), SLOT(onDisconnect(Jreen::Client::DisconnectReason)));
|
||||
connect(m_client, SIGNAL(newMessage(Jreen::Message)), SLOT(onNewMessage(Jreen::Message)));
|
||||
connect(m_client, SIGNAL(messageReceived(Jreen::Message)), SLOT(onNewMessage(Jreen::Message)));
|
||||
|
||||
connect(m_client, SIGNAL(newIQ(Jreen::IQ)), SLOT(onNewIq(Jreen::IQ)));
|
||||
connect(m_client, SIGNAL(iqReceived(Jreen::IQ)), SLOT(onNewIq(Jreen::IQ)));
|
||||
|
||||
connect(m_roster, SIGNAL(presenceReceived(Jreen::RosterItem::Ptr,Jreen::Presence)),
|
||||
SLOT(onPresenceReceived(Jreen::RosterItem::Ptr,Jreen::Presence)));
|
||||
@ -157,10 +158,10 @@ JabberPlugin::refreshProxy()
|
||||
|
||||
if( !m_client->connection() )
|
||||
return;
|
||||
|
||||
|
||||
QNetworkProxy proxyToUse = TomahawkUtils::proxyFactory()->queryProxy( QNetworkProxyQuery( m_currentServer, m_currentPort ) ).first();
|
||||
m_usedProxy = proxyToUse;
|
||||
|
||||
|
||||
if( proxyToUse.type() != QNetworkProxy::NoProxy && ( m_currentServer.isEmpty() || !(m_currentPort > 0) ) )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << " proxy type is not noproxy but no server/port set";
|
||||
@ -445,8 +446,9 @@ JabberPlugin::sendMsg(const QString& to, const QString& msg)
|
||||
qDebug() << "Send sip messsage to " << to;
|
||||
Jreen::IQ iq( Jreen::IQ::Set, to );
|
||||
iq.addExtension( sipMessage );
|
||||
|
||||
m_client->send( iq, this, SLOT( onNewIq( Jreen::IQ, int ) ), SipMessageSent );
|
||||
Jreen::IQReply *reply = m_client->send(iq);
|
||||
reply->setData(SipMessageSent);
|
||||
connect(reply, SIGNAL(received(Jreen::IQ)), SLOT(onNewIq(Jreen::IQ)));
|
||||
}
|
||||
|
||||
void
|
||||
@ -467,7 +469,12 @@ void
|
||||
JabberPlugin::addContact(const QString& jid, const QString& msg)
|
||||
{
|
||||
// Add contact to the Tomahawk group on the roster
|
||||
m_roster->subscribe( jid, msg, jid, QStringList() << "Tomahawk" );
|
||||
|
||||
QString realJid = jid;
|
||||
if( !realJid.contains( '@' ) )
|
||||
realJid += defaultSuffix();
|
||||
|
||||
m_roster->subscribe( realJid, msg, realJid, QStringList() << "Tomahawk" );
|
||||
|
||||
return;
|
||||
}
|
||||
@ -486,6 +493,13 @@ JabberPlugin::showAddFriendDialog()
|
||||
addContact( id );
|
||||
}
|
||||
|
||||
QString
|
||||
JabberPlugin::defaultSuffix() const
|
||||
{
|
||||
return "@jabber.org";
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JabberPlugin::showXmlConsole()
|
||||
{
|
||||
@ -513,13 +527,19 @@ JabberPlugin::checkSettings()
|
||||
proxyToUse.type() != m_usedProxy.type() ||
|
||||
proxyToUse.capabilities() != m_usedProxy.capabilities()
|
||||
)
|
||||
reconnect = true;
|
||||
reconnect = true;
|
||||
|
||||
m_currentUsername = accountName();
|
||||
m_currentPassword = readPassword();
|
||||
m_currentServer = readServer();
|
||||
m_currentPort = readPort();
|
||||
|
||||
if ( !m_currentUsername.contains( '@' ) )
|
||||
{
|
||||
m_currentUsername += defaultSuffix();
|
||||
TomahawkSettings::instance()->setValue( pluginId() + "/username", m_currentUsername );
|
||||
}
|
||||
|
||||
if ( reconnect )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << "Reconnecting jreen plugin...";
|
||||
@ -540,7 +560,6 @@ JabberPlugin::checkSettings()
|
||||
void JabberPlugin::setupClientHelper()
|
||||
{
|
||||
Jreen::JID jid = Jreen::JID( m_currentUsername );
|
||||
|
||||
m_client->setJID( jid );
|
||||
m_client->setPassword( m_currentPassword );
|
||||
|
||||
@ -648,7 +667,7 @@ void JabberPlugin::onPresenceReceived( const Jreen::RosterItem::Ptr &item, const
|
||||
}
|
||||
|
||||
// ignore anyone not Running tomahawk:
|
||||
Jreen::Capabilities::Ptr caps = presence.findExtension<Jreen::Capabilities>();
|
||||
Jreen::Capabilities::Ptr caps = presence.payload<Jreen::Capabilities>();
|
||||
/* Disabled this, because it's somewhat ugly and we should rely on nothing but the features
|
||||
if ( caps && ( caps->node() == TOMAHAWK_CAP_NODE_NAME ) )
|
||||
{
|
||||
@ -666,8 +685,10 @@ void JabberPlugin::onPresenceReceived( const Jreen::RosterItem::Ptr &item, const
|
||||
|
||||
Jreen::IQ featuresIq( Jreen::IQ::Get, jid );
|
||||
featuresIq.addExtension( new Jreen::Disco::Info( node ) );
|
||||
|
||||
m_client->send( featuresIq, this, SLOT( onNewIq( Jreen::IQ, int ) ), RequestDisco );
|
||||
|
||||
Jreen::IQReply *reply = m_client->send(featuresIq);
|
||||
reply->setData(RequestDisco);
|
||||
connect(reply, SIGNAL(received(Jreen::IQ)), SLOT(onNewIq(Jreen::IQ)));
|
||||
}
|
||||
else if( !caps )
|
||||
{
|
||||
@ -761,15 +782,18 @@ JabberPlugin::onSubscriptionRequestConfirmed( int result )
|
||||
m_roster->allowSubscription( jid, allowSubscription == QMessageBox::Yes );
|
||||
}
|
||||
|
||||
void JabberPlugin::onNewIq(const Jreen::IQ& iq, int context)
|
||||
void JabberPlugin::onNewIq(const Jreen::IQ& iq)
|
||||
{
|
||||
if ( m_state != Connected )
|
||||
return;
|
||||
|
||||
Jreen::IQReply *reply = qobject_cast<Jreen::IQReply*>(sender());
|
||||
int context = reply ? reply->data().toInt() : NoContext;
|
||||
|
||||
if( context == RequestDisco )
|
||||
{
|
||||
// qDebug() << Q_FUNC_INFO << "Received disco IQ...";
|
||||
Jreen::Disco::Info *discoInfo = iq.findExtension<Jreen::Disco::Info>().data();
|
||||
Jreen::Disco::Info *discoInfo = iq.payload<Jreen::Disco::Info>().data();
|
||||
if(!discoInfo)
|
||||
return;
|
||||
iq.accept();
|
||||
@ -803,7 +827,7 @@ void JabberPlugin::onNewIq(const Jreen::IQ& iq, int context)
|
||||
}
|
||||
else if(context == RequestVersion)
|
||||
{
|
||||
Jreen::SoftwareVersion* softwareVersion = iq.findExtension<Jreen::SoftwareVersion>().data();
|
||||
Jreen::SoftwareVersion::Ptr softwareVersion = iq.payload<Jreen::SoftwareVersion>();
|
||||
if( softwareVersion )
|
||||
{
|
||||
QString versionString = QString("%1 %2 %3").arg( softwareVersion->name(), softwareVersion->os(), softwareVersion->version() );
|
||||
@ -825,7 +849,7 @@ void JabberPlugin::onNewIq(const Jreen::IQ& iq, int context)
|
||||
}*/
|
||||
else
|
||||
{
|
||||
TomahawkSipMessage *sipMessage = iq.findExtension<TomahawkSipMessage>().data();
|
||||
TomahawkSipMessage::Ptr sipMessage = iq.payload<TomahawkSipMessage>();
|
||||
if(sipMessage)
|
||||
{
|
||||
iq.accept();
|
||||
@ -910,7 +934,9 @@ void JabberPlugin::handlePeerStatus(const Jreen::JID& jid, Jreen::Presence::Type
|
||||
// request software version
|
||||
Jreen::IQ versionIq( Jreen::IQ::Get, jid );
|
||||
versionIq.addExtension( new Jreen::SoftwareVersion() );
|
||||
m_client->send( versionIq, this, SLOT( onNewIq( Jreen::IQ, int ) ), RequestVersion );
|
||||
Jreen::IQReply *reply = m_client->send(versionIq);
|
||||
reply->setData(RequestVersion);
|
||||
connect(reply, SIGNAL(received(Jreen::IQ)), SLOT(onNewIq(Jreen::IQ)));
|
||||
|
||||
return;
|
||||
}
|
||||
@ -981,6 +1007,12 @@ JabberPlugin::saveConfig()
|
||||
checkSettings();
|
||||
}
|
||||
|
||||
void
|
||||
JabberPlugin::deletePlugin()
|
||||
{
|
||||
TomahawkSettings::instance()->remove( pluginId() );
|
||||
}
|
||||
|
||||
|
||||
SipPlugin::ConnectionState
|
||||
JabberPlugin::connectionState() const
|
||||
|
@ -82,6 +82,7 @@ public:
|
||||
virtual QIcon icon() const;
|
||||
virtual QWidget* configWidget();
|
||||
virtual void saveConfig();
|
||||
virtual void deletePlugin();
|
||||
|
||||
signals:
|
||||
void jidChanged( const QString& );
|
||||
@ -94,12 +95,14 @@ public slots:
|
||||
void broadcastMsg( const QString &msg );
|
||||
void addContact( const QString &jid, const QString& msg = QString() );
|
||||
void refreshProxy();
|
||||
void showAddFriendDialog();
|
||||
|
||||
protected:
|
||||
virtual QString defaultSuffix() const;
|
||||
|
||||
Ui_JabberConfig* m_ui; // so the google wrapper can change the config dialog a bit
|
||||
|
||||
private slots:
|
||||
void showAddFriendDialog();
|
||||
void showXmlConsole();
|
||||
void onConnect();
|
||||
void onDisconnect(Jreen::Client::DisconnectReason reason);
|
||||
@ -113,7 +116,7 @@ private slots:
|
||||
{
|
||||
qDebug() << e;
|
||||
}
|
||||
void onNewIq( const Jreen::IQ &iq, int context = NoContext );
|
||||
void onNewIq( const Jreen::IQ &iq );
|
||||
void onNewAvatar( const QString &jid );
|
||||
|
||||
private:
|
||||
|
@ -8,9 +8,9 @@
|
||||
#include "../sipdllmacro.h"
|
||||
|
||||
class TomahawkSipMessagePrivate;
|
||||
class SIPDLLEXPORT TomahawkSipMessage : public Jreen::StanzaExtension
|
||||
class SIPDLLEXPORT TomahawkSipMessage : public Jreen::Payload
|
||||
{
|
||||
J_EXTENSION(TomahawkSipMessage, "")
|
||||
J_PAYLOAD(TomahawkSipMessage)
|
||||
Q_DECLARE_PRIVATE(TomahawkSipMessage)
|
||||
public:
|
||||
// sets visible to true
|
||||
|
@ -86,7 +86,7 @@ void TomahawkSipMessageFactory::handleCharacterData(const QStringRef &text)
|
||||
Q_UNUSED(text);
|
||||
}
|
||||
|
||||
void TomahawkSipMessageFactory::serialize(StanzaExtension *extension, QXmlStreamWriter *writer)
|
||||
void TomahawkSipMessageFactory::serialize(Payload *extension, QXmlStreamWriter *writer)
|
||||
{
|
||||
TomahawkSipMessage *sipMessage = se_cast<TomahawkSipMessage*>(extension);
|
||||
|
||||
@ -118,10 +118,10 @@ void TomahawkSipMessageFactory::serialize(StanzaExtension *extension, QXmlStream
|
||||
writer->writeEndElement();
|
||||
}
|
||||
|
||||
StanzaExtension::Ptr TomahawkSipMessageFactory::createExtension()
|
||||
Payload::Ptr TomahawkSipMessageFactory::createPayload()
|
||||
{
|
||||
if(m_visible)
|
||||
return StanzaExtension::Ptr(new TomahawkSipMessage(m_ip, m_port, m_uniqname, m_key));
|
||||
return Payload::Ptr(new TomahawkSipMessage(m_ip, m_port, m_uniqname, m_key));
|
||||
else
|
||||
return StanzaExtension::Ptr(new TomahawkSipMessage());
|
||||
return Payload::Ptr(new TomahawkSipMessage());
|
||||
}
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
#include "../sipdllmacro.h"
|
||||
|
||||
class SIPDLLEXPORT TomahawkSipMessageFactory : public Jreen::StanzaExtensionFactory<TomahawkSipMessage>
|
||||
class SIPDLLEXPORT TomahawkSipMessageFactory : public Jreen::PayloadFactory<TomahawkSipMessage>
|
||||
{
|
||||
public:
|
||||
TomahawkSipMessageFactory();
|
||||
@ -33,8 +33,8 @@ public:
|
||||
void handleStartElement(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes);
|
||||
void handleEndElement(const QStringRef &name, const QStringRef &uri);
|
||||
void handleCharacterData(const QStringRef &text);
|
||||
void serialize(Jreen::StanzaExtension *extension, QXmlStreamWriter *writer);
|
||||
Jreen::StanzaExtension::Ptr createExtension();
|
||||
void serialize(Jreen::Payload *extension, QXmlStreamWriter *writer);
|
||||
Jreen::Payload::Ptr createPayload();
|
||||
private:
|
||||
enum State { AtNowhere, AtTransport, AtCandidate } m_state;
|
||||
int m_depth;
|
||||
|
@ -2,11 +2,8 @@
|
||||
#include <QInputDialog>
|
||||
#include <QDebug>
|
||||
|
||||
#define CONSUMER_KEY "C4v4Wfa21rfIDck4HMR3A"
|
||||
#define CONSUMER_SECRET "zXSjU6bjrvg6UVMJX4JufqHyjj3iextY14SR9uBEAo"
|
||||
|
||||
TomahawkOAuthTwitter::TomahawkOAuthTwitter( QNetworkAccessManager *nam, QObject* parent )
|
||||
: OAuthTwitter( CONSUMER_KEY, CONSUMER_SECRET, parent )
|
||||
: OAuthTwitter( QByteArray( "C4v4Wfa21rfIDck4HMR3A" ), QByteArray( "zXSjU6bjrvg6UVMJX4JufqHyjj3iextY14SR9uBEAo" ), parent )
|
||||
{
|
||||
setNetworkAccessManager( nam );
|
||||
}
|
||||
|
@ -283,6 +283,12 @@ TwitterPlugin::connectAuthVerifyReply( const QTweetUser &user )
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TwitterPlugin::deletePlugin()
|
||||
{
|
||||
TomahawkSettings::instance()->remove( pluginId() );
|
||||
}
|
||||
|
||||
void
|
||||
TwitterPlugin::checkTimerFired()
|
||||
{
|
||||
@ -596,7 +602,7 @@ TwitterPlugin::registerOffer( const QString &screenName, const QHash< QString, Q
|
||||
|
||||
if ( !m_cachedAvatars.contains( screenName ) )
|
||||
QMetaObject::invokeMethod( this, "fetchAvatar", Q_ARG( QString, screenName ) );
|
||||
|
||||
|
||||
QHash< QString, QVariant > _peerData( peerData );
|
||||
|
||||
if ( _peerData.contains( "dirty" ) )
|
||||
@ -906,7 +912,7 @@ TwitterPlugin::twitterCachedFriendsSinceId() const
|
||||
s->sync();
|
||||
}
|
||||
s->endGroup();
|
||||
|
||||
|
||||
return s->value( pluginId() + "/cachedfriendssinceid", 0 ).toLongLong();
|
||||
}
|
||||
|
||||
@ -1004,7 +1010,7 @@ TwitterPlugin::twitterCachedPeers() const
|
||||
s->setValue( "cachedpeers",
|
||||
s->value( "cachedpeers_tmp" ).toHash() );
|
||||
s->remove( "cachedpeers_tmp" );
|
||||
|
||||
|
||||
s->sync();
|
||||
}
|
||||
s->endGroup();
|
||||
|
@ -74,12 +74,13 @@ public:
|
||||
|
||||
signals:
|
||||
void avatarReceived( QString, QPixmap );
|
||||
|
||||
|
||||
public slots:
|
||||
virtual bool connectPlugin( bool startup );
|
||||
void disconnectPlugin();
|
||||
void checkSettings();
|
||||
void refreshProxy();
|
||||
void deletePlugin();
|
||||
|
||||
void sendMsg( const QString& to, const QString& msg )
|
||||
{
|
||||
@ -135,8 +136,6 @@ private:
|
||||
void setTwitterCachedDirectMessagesSinceId( qint64 sinceid );
|
||||
QHash<QString, QVariant> twitterCachedPeers() const;
|
||||
void setTwitterCachedPeers( const QHash<QString, QVariant> &cachedPeers );
|
||||
bool twitterAutoConnect() const;
|
||||
void setTwitterAutoConnect( bool autoConnect );
|
||||
|
||||
QWeakPointer< TomahawkOAuthTwitter > m_twitterAuth;
|
||||
QWeakPointer< QTweetFriendsTimeline > m_friendsTimeline;
|
||||
|
@ -132,6 +132,7 @@ TwitterConfigWidget::authenticateVerifyReply( const QTweetUser &user )
|
||||
m_plugin->connectPlugin( false );
|
||||
|
||||
emit twitterAuthed( true );
|
||||
emit sizeHintChanged();
|
||||
}
|
||||
|
||||
void
|
||||
@ -161,6 +162,7 @@ TwitterConfigWidget::deauthenticateTwitter()
|
||||
ui->twitterTweetComboBox->setVisible( false );
|
||||
|
||||
emit twitterAuthed( false );
|
||||
emit sizeHintChanged();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -45,6 +45,7 @@ public:
|
||||
signals:
|
||||
void twitterAuthed( bool authed );
|
||||
|
||||
void sizeHintChanged();
|
||||
private slots:
|
||||
void authDeauthTwitter();
|
||||
void startPostGotTomahawkStatus();
|
||||
|
@ -143,10 +143,20 @@ SourceTreeView::setupMenus()
|
||||
m_copyPlaylistAction = m_playlistMenu.addAction( tr( "&Copy Link" ) );
|
||||
m_deletePlaylistAction = m_playlistMenu.addAction( tr( "&Delete %1" ).arg( SourcesModel::rowTypeToString( type ) ) );
|
||||
|
||||
m_roPlaylistMenu.addAction( m_copyPlaylistAction );
|
||||
QString addToText = QString( "Add to my %1" );
|
||||
if ( type == SourcesModel::StaticPlaylist )
|
||||
addToText = addToText.arg( "Playlists" );
|
||||
if ( type == SourcesModel::AutomaticPlaylist )
|
||||
addToText = addToText.arg( "Automatic Playlists" );
|
||||
else if ( type == SourcesModel::Station )
|
||||
addToText = addToText.arg( "Stations" );
|
||||
|
||||
m_addToLocalAction = m_roPlaylistMenu.addAction( tr( addToText.toUtf8(), "Adds the given playlist, dynamic playlist, or station to the users's own list" ) );
|
||||
|
||||
m_roPlaylistMenu.addAction( m_copyPlaylistAction );
|
||||
m_deletePlaylistAction->setEnabled( !readonly );
|
||||
m_renamePlaylistAction->setEnabled( !readonly );
|
||||
m_addToLocalAction->setEnabled( readonly );
|
||||
|
||||
if ( type == SourcesModel::StaticPlaylist )
|
||||
m_copyPlaylistAction->setText( tr( "&Export Playlist" ) );
|
||||
@ -155,6 +165,7 @@ SourceTreeView::setupMenus()
|
||||
connect( m_renamePlaylistAction, SIGNAL( triggered() ), SLOT( renamePlaylist() ) );
|
||||
connect( m_deletePlaylistAction, SIGNAL( triggered() ), SLOT( deletePlaylist() ) );
|
||||
connect( m_copyPlaylistAction, SIGNAL( triggered() ), SLOT( copyPlaylistLink() ) );
|
||||
connect( m_addToLocalAction, SIGNAL( triggered() ), SLOT( addToLocal() ) );
|
||||
}
|
||||
|
||||
|
||||
@ -259,6 +270,36 @@ SourceTreeView::copyPlaylistLink()
|
||||
}
|
||||
}
|
||||
|
||||
void SourceTreeView::addToLocal()
|
||||
{
|
||||
QModelIndex idx = m_contextMenuIndex;
|
||||
if ( !idx.isValid() )
|
||||
return;
|
||||
|
||||
SourcesModel::RowType type = ( SourcesModel::RowType )model()->data( m_contextMenuIndex, SourcesModel::SourceTreeItemTypeRole ).toInt();
|
||||
if( type == SourcesModel::AutomaticPlaylist || type == SourcesModel::Station )
|
||||
{
|
||||
DynamicPlaylistItem* item = itemFromIndex< DynamicPlaylistItem >( m_contextMenuIndex );
|
||||
dynplaylist_ptr playlist = item->dynPlaylist();
|
||||
|
||||
// copy to a link and then generate a new playlist from that
|
||||
// this way we cheaply regenerate the needed controls
|
||||
QString link = GlobalActionManager::instance()->copyPlaylistToClipboard( playlist );
|
||||
dynplaylist_ptr p = GlobalActionManager::instance()->loadDynamicPlaylist( link, type == SourcesModel::Station );
|
||||
} else if ( type == SourcesModel::StaticPlaylist )
|
||||
{
|
||||
PlaylistItem* item = itemFromIndex< PlaylistItem >( m_contextMenuIndex );
|
||||
playlist_ptr playlist = item->playlist();
|
||||
|
||||
// just create the new playlist with the same values
|
||||
QList< query_ptr > queries;
|
||||
foreach( const plentry_ptr& e, playlist->entries() )
|
||||
queries << e->query();
|
||||
|
||||
playlist_ptr newpl = Playlist::create( SourceList::instance()->getLocal(), uuid(), playlist->title(), playlist->info(), playlist->creator(), playlist->shared(), queries );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SourceTreeView::renamePlaylist()
|
||||
|
@ -54,6 +54,7 @@ private slots:
|
||||
void loadPlaylist();
|
||||
void deletePlaylist( const QModelIndex& = QModelIndex() );
|
||||
void copyPlaylistLink();
|
||||
void addToLocal();
|
||||
|
||||
void onCustomContextMenu( const QPoint& pos );
|
||||
protected:
|
||||
@ -84,6 +85,7 @@ private:
|
||||
QAction* m_renamePlaylistAction;
|
||||
QAction* m_deletePlaylistAction;
|
||||
QAction* m_copyPlaylistAction;
|
||||
QAction* m_addToLocalAction;
|
||||
|
||||
bool m_dragging;
|
||||
QRect m_dropRect;
|
||||
|
@ -363,6 +363,45 @@ entire directories at once (so is not good for very flat collections).</string>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="nowPlaying">
|
||||
<property name="title">
|
||||
<string>Now Playing Information</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2" stretch="0,0">
|
||||
<property name="margin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Applications to update with currently playing track:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBoxEnableAdium">
|
||||
<property name="text">
|
||||
<string>Adium</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">
|
||||
|
@ -1,12 +0,0 @@
|
||||
[Protocol]
|
||||
exec=/home/leo/kde/tomahawk/build/tomahawk "%u"
|
||||
protocol=tomahawk
|
||||
input=none
|
||||
output=none
|
||||
helper=true
|
||||
listing=
|
||||
reading=false
|
||||
writing=false
|
||||
makedir=false
|
||||
deleting=false
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
#include "tomahawkwindow.h"
|
||||
#include "ui_tomahawkwindow.h"
|
||||
#include "ui_searchbox.h"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
@ -28,6 +29,7 @@
|
||||
#include <QInputDialog>
|
||||
#include <QPixmap>
|
||||
#include <QPropertyAnimation>
|
||||
#include <QLineEdit>
|
||||
#include <QMessageBox>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
@ -50,6 +52,7 @@
|
||||
#include "utils/widgetdragfilter.h"
|
||||
#include "utils/xspfloader.h"
|
||||
#include "widgets/newplaylistwidget.h"
|
||||
#include "widgets/searchwidget.h"
|
||||
#include "widgets/playlisttypeselectordlg.h"
|
||||
|
||||
#include "audiocontrols.h"
|
||||
@ -57,6 +60,7 @@
|
||||
#include "diagnosticsdialog.h"
|
||||
#include "tomahawksettings.h"
|
||||
#include "sourcelist.h"
|
||||
#include "PipelineStatusView.h"
|
||||
#include "transferview.h"
|
||||
#include "tomahawktrayicon.h"
|
||||
#include "playlist/dynamic/GeneratorInterface.h"
|
||||
@ -73,6 +77,7 @@ using namespace Tomahawk;
|
||||
TomahawkWindow::TomahawkWindow( QWidget* parent )
|
||||
: QMainWindow( parent )
|
||||
, ui( new Ui::TomahawkWindow )
|
||||
, m_searchWidget( new Ui::GlobalSearchWidget )
|
||||
, m_audioControls( new AudioControls( this ) )
|
||||
, m_trayIcon( new TomahawkTrayIcon( this ) )
|
||||
, m_sourcetree( 0 )
|
||||
@ -91,7 +96,9 @@ TomahawkWindow::TomahawkWindow( QWidget* parent )
|
||||
connect( m_audioControls, SIGNAL( playPressed() ), pm, SLOT( onPlayClicked() ) );
|
||||
connect( m_audioControls, SIGNAL( pausePressed() ), pm, SLOT( onPauseClicked() ) );
|
||||
|
||||
m_searchBox = new QWidget();
|
||||
ui->setupUi( this );
|
||||
m_searchWidget->setupUi( m_searchBox );
|
||||
|
||||
delete ui->sidebarWidget;
|
||||
delete ui->playlistWidget;
|
||||
@ -107,18 +114,19 @@ TomahawkWindow::TomahawkWindow( QWidget* parent )
|
||||
sidebar->setOrientation( Qt::Vertical );
|
||||
sidebar->setChildrenCollapsible( false );
|
||||
sidebar->setGreedyWidget( 0 );
|
||||
sidebar->setStretchFactor( 0, 3 );
|
||||
sidebar->setStretchFactor( 1, 1 );
|
||||
|
||||
m_sourcetree = new SourceTreeView();
|
||||
TransferView* transferView = new TransferView();
|
||||
TransferView* transferView = new TransferView( sidebar );
|
||||
PipelineStatusView* pipelineView = new PipelineStatusView( sidebar );
|
||||
|
||||
connect( ui->actionHideOfflineSources, SIGNAL( triggered() ), m_sourcetree, SLOT( hideOfflineSources() ) );
|
||||
connect( ui->actionShowOfflineSources, SIGNAL( triggered() ), m_sourcetree, SLOT( showOfflineSources() ) );
|
||||
|
||||
sidebar->addWidget( m_sourcetree );
|
||||
sidebar->addWidget( transferView );
|
||||
sidebar->addWidget( pipelineView );
|
||||
sidebar->hide( 1, false );
|
||||
sidebar->hide( 2, false );
|
||||
|
||||
/* QWidget* buttonWidget = new QWidget();
|
||||
buttonWidget->setLayout( new QVBoxLayout() );
|
||||
@ -184,6 +192,14 @@ TomahawkWindow::TomahawkWindow( QWidget* parent )
|
||||
m_forwardAvailable = toolbar->addAction( QIcon( RESPATH "images/forward.png" ), tr( "Forward" ), ViewManager::instance(), SLOT( historyForward() ) );
|
||||
m_forwardAvailable->setToolTip( tr( "Go forward one page" ) );
|
||||
|
||||
m_searchWidget->searchEdit->setStyleSheet( "QLineEdit { border: 1px solid gray; border-radius: 6px; margin-right: 2px; }" );
|
||||
#ifdef Q_WS_MAC
|
||||
m_searchWidget->searchEdit->setAttribute( Qt::WA_MacShowFocusRect, 0 );
|
||||
#endif
|
||||
|
||||
connect( m_searchWidget->searchEdit, SIGNAL( returnPressed() ), SLOT( onSearch() ) );
|
||||
toolbar->addWidget( m_searchBox );
|
||||
|
||||
statusBar()->addPermanentWidget( m_audioControls, 1 );
|
||||
|
||||
// propagate sip menu
|
||||
@ -495,14 +511,17 @@ TomahawkWindow::createPlaylist()
|
||||
PlaylistTypeSelectorDlg playlistSelectorDlg;
|
||||
int successfulReturn = playlistSelectorDlg.exec();
|
||||
|
||||
if ( !playlistSelectorDlg.playlistTypeIsAuto() && successfulReturn ) {
|
||||
|
||||
if ( !playlistSelectorDlg.playlistTypeIsAuto() && successfulReturn )
|
||||
{
|
||||
// only show if none is shown yet
|
||||
if( !ViewManager::instance()->isNewPlaylistPageVisible() ) {
|
||||
if ( !ViewManager::instance()->isNewPlaylistPageVisible() )
|
||||
{
|
||||
ViewManager::instance()->show( new NewPlaylistWidget() );
|
||||
}
|
||||
|
||||
} else if ( playlistSelectorDlg.playlistTypeIsAuto() && successfulReturn ) {
|
||||
}
|
||||
else if ( playlistSelectorDlg.playlistTypeIsAuto() && successfulReturn )
|
||||
{
|
||||
// create Auto Playlist
|
||||
QString playlistName = playlistSelectorDlg.playlistName();
|
||||
APP->mainWindow()->createAutomaticPlaylist( playlistName );
|
||||
@ -607,13 +626,23 @@ TomahawkWindow::checkForUpdates()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TomahawkWindow::onSearch()
|
||||
{
|
||||
ViewManager::instance()->show( new SearchWidget( m_searchWidget->searchEdit->text(), this ) );
|
||||
m_searchWidget->searchEdit->setText( QString() );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TomahawkWindow::minimize()
|
||||
{
|
||||
if ( isMinimized() )
|
||||
{
|
||||
showNormal();
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
showMinimized();
|
||||
}
|
||||
}
|
||||
@ -625,7 +654,9 @@ TomahawkWindow::maximize()
|
||||
if ( isMaximized() )
|
||||
{
|
||||
showNormal();
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
showMaximized();
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ class TomahawkTrayIcon;
|
||||
namespace Ui
|
||||
{
|
||||
class TomahawkWindow;
|
||||
class GlobalSearchWidget;
|
||||
}
|
||||
|
||||
class TomahawkWindow : public QMainWindow
|
||||
@ -89,6 +90,8 @@ private slots:
|
||||
void onSipPluginAdded( SipPlugin* p );
|
||||
void onSipPluginRemoved( SipPlugin* p );
|
||||
|
||||
void onSearch();
|
||||
|
||||
void minimize();
|
||||
void maximize();
|
||||
|
||||
@ -98,6 +101,8 @@ private:
|
||||
void setupSignals();
|
||||
|
||||
Ui::TomahawkWindow* ui;
|
||||
Ui::GlobalSearchWidget* m_searchWidget;
|
||||
QWidget* m_searchBox;
|
||||
AudioControls* m_audioControls;
|
||||
TomahawkTrayIcon* m_trayIcon;
|
||||
SourceTreeView* m_sourcetree;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
@ -80,12 +80,6 @@ TransferView::streamFinished( StreamConnection* sc )
|
||||
emit showWidget();
|
||||
else
|
||||
emit hideWidget();
|
||||
|
||||
/* if ( m_index.contains( sc ) )
|
||||
{
|
||||
int i = m_index.value( sc );
|
||||
m_tree->invisibleRootItem()->child( i )->setText( 1, tr( "Finished" ) );
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
@ -32,7 +32,7 @@ class TransferView : public AnimatedWidget
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit TransferView( AnimatedSplitter* parent = 0 );
|
||||
explicit TransferView( AnimatedSplitter* parent );
|
||||
virtual ~TransferView()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
|
3
thirdparty/CMakeLists.txt
vendored
3
thirdparty/CMakeLists.txt
vendored
@ -1,2 +1,5 @@
|
||||
ADD_SUBDIRECTORY( qxt )
|
||||
ADD_SUBDIRECTORY( liblastfm2 )
|
||||
IF( APPLE )
|
||||
ADD_SUBDIRECTORY( SPMediaKeyTap )
|
||||
ENDIF()
|
||||
|
13
thirdparty/SPMediaKeyTap/CMakeLists.txt
vendored
Normal file
13
thirdparty/SPMediaKeyTap/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
set(SPMEDIAKEY-SOURCES
|
||||
SPMediaKeyTap.m
|
||||
SPInvocationGrabbing/NSObject+SPInvocationGrabbing.m
|
||||
)
|
||||
|
||||
set(SPMEDIAKEY-HEADERS
|
||||
SPMediaKeyTap.h
|
||||
SPInvocationGrabbing/NSObject+SPInvocationGrabbing.h
|
||||
)
|
||||
|
||||
ADD_LIBRARY(SPMediaKeyTap STATIC
|
||||
${SPMEDIAKEY-SOURCES}
|
||||
)
|
8
thirdparty/SPMediaKeyTap/LICENSE
vendored
Normal file
8
thirdparty/SPMediaKeyTap/LICENSE
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
Copyright (c) 2011, Joachim Bengtsson
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Neither the name of the organization nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
12
thirdparty/SPMediaKeyTap/README.md
vendored
Normal file
12
thirdparty/SPMediaKeyTap/README.md
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
SPMediaKeyTap
|
||||
=============
|
||||
|
||||
`SPMediaKeyTap` abstracts a `CGEventHook` and other nastiness in order to give you a relatively simple API to receive media key events (prev/next/playpause, on F7 to F9 on modern MacBook Pros) exclusively, without them reaching other applications like iTunes. `SPMediaKeyTap` is clever enough to resign its exclusive lock on media keys by looking for which application was active most recently: if that application is in `SPMediaKeyTap`'s whitelist, it will resign the keys. This is similar to the behavior of Apple's applications collaborating on media key handling exclusivity, but unfortunately, Apple are not exposing any APIs allowing third-parties to join in on this collaboration.
|
||||
|
||||
For now, the whitelist is just a hardcoded array in `+[SPMediaKeyTap defaultMediaKeyUserBundleIdentifiers]`. If your app starts using `SPMediaKeyTap`, please [mail me](mailto:nevyn@spotify.com) your bundle ID, and I'll include it in the canonical repository. This is a bad solution; a better solution would be to use distributed notifications to collaborate in creating this whitelist at runtime. Hopefully someone'll have the time and energy to write this soon.
|
||||
|
||||
In `Example/SPMediaKeyTapExampleAppDelegate.m` is an example of both how you use `SPMediaKeyTap`, and how you handle the semi-private `NSEvent` subtypes involved in media keys, including on how to fall back to non-event tap handling of these events.
|
||||
|
||||
`SPMediaKeyTap` and other `CGEventHook`s on the event type `NSSystemDefined` is known to interfere with each other and applications doing weird stuff with mouse input, because mouse clicks are also part of the `NSSystemDefined` category. The single issue we have had reported here at Spotify is Adobe Fireworks, in which item selection stops working with `SPMediaKeyTap` is active.
|
||||
|
||||
`SPMediaKeyTap` requires 10.5 to work, and disables itself on 10.4.
|
30
thirdparty/SPMediaKeyTap/SPInvocationGrabbing/NSObject+SPInvocationGrabbing.h
vendored
Normal file
30
thirdparty/SPMediaKeyTap/SPInvocationGrabbing/NSObject+SPInvocationGrabbing.h
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface SPInvocationGrabber : NSObject {
|
||||
id _object;
|
||||
NSInvocation *_invocation;
|
||||
int frameCount;
|
||||
char **frameStrings;
|
||||
BOOL backgroundAfterForward;
|
||||
BOOL onMainAfterForward;
|
||||
BOOL waitUntilDone;
|
||||
}
|
||||
-(id)initWithObject:(id)obj;
|
||||
-(id)initWithObject:(id)obj stacktraceSaving:(BOOL)saveStack;
|
||||
@property (readonly, retain, nonatomic) id object;
|
||||
@property (readonly, retain, nonatomic) NSInvocation *invocation;
|
||||
@property BOOL backgroundAfterForward;
|
||||
@property BOOL onMainAfterForward;
|
||||
@property BOOL waitUntilDone;
|
||||
-(void)invoke; // will release object and invocation
|
||||
-(void)printBacktrace;
|
||||
-(void)saveBacktrace;
|
||||
@end
|
||||
|
||||
@interface NSObject (SPInvocationGrabbing)
|
||||
-(id)grab;
|
||||
-(id)invokeAfter:(NSTimeInterval)delta;
|
||||
-(id)nextRunloop;
|
||||
-(id)inBackground;
|
||||
-(id)onMainAsync:(BOOL)async;
|
||||
@end
|
128
thirdparty/SPMediaKeyTap/SPInvocationGrabbing/NSObject+SPInvocationGrabbing.m
vendored
Normal file
128
thirdparty/SPMediaKeyTap/SPInvocationGrabbing/NSObject+SPInvocationGrabbing.m
vendored
Normal file
@ -0,0 +1,128 @@
|
||||
#import "NSObject+SPInvocationGrabbing.h"
|
||||
#import <execinfo.h>
|
||||
|
||||
#pragma mark Invocation grabbing
|
||||
@interface SPInvocationGrabber ()
|
||||
@property (readwrite, retain, nonatomic) id object;
|
||||
@property (readwrite, retain, nonatomic) NSInvocation *invocation;
|
||||
|
||||
@end
|
||||
|
||||
@implementation SPInvocationGrabber
|
||||
- (id)initWithObject:(id)obj;
|
||||
{
|
||||
return [self initWithObject:obj stacktraceSaving:YES];
|
||||
}
|
||||
|
||||
-(id)initWithObject:(id)obj stacktraceSaving:(BOOL)saveStack;
|
||||
{
|
||||
self.object = obj;
|
||||
|
||||
if(saveStack)
|
||||
[self saveBacktrace];
|
||||
|
||||
return self;
|
||||
}
|
||||
-(void)dealloc;
|
||||
{
|
||||
free(frameStrings);
|
||||
self.object = nil;
|
||||
self.invocation = nil;
|
||||
[super dealloc];
|
||||
}
|
||||
@synthesize invocation = _invocation, object = _object;
|
||||
|
||||
@synthesize backgroundAfterForward, onMainAfterForward, waitUntilDone;
|
||||
- (void)runInBackground;
|
||||
{
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
@try {
|
||||
[self invoke];
|
||||
}
|
||||
@finally {
|
||||
[pool drain];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void)forwardInvocation:(NSInvocation *)anInvocation {
|
||||
[anInvocation retainArguments];
|
||||
anInvocation.target = _object;
|
||||
self.invocation = anInvocation;
|
||||
|
||||
if(backgroundAfterForward)
|
||||
[NSThread detachNewThreadSelector:@selector(runInBackground) toTarget:self withObject:nil];
|
||||
else if(onMainAfterForward)
|
||||
[self performSelectorOnMainThread:@selector(invoke) withObject:nil waitUntilDone:waitUntilDone];
|
||||
}
|
||||
- (NSMethodSignature *)methodSignatureForSelector:(SEL)inSelector {
|
||||
NSMethodSignature *signature = [super methodSignatureForSelector:inSelector];
|
||||
if (signature == NULL)
|
||||
signature = [_object methodSignatureForSelector:inSelector];
|
||||
|
||||
return signature;
|
||||
}
|
||||
|
||||
- (void)invoke;
|
||||
{
|
||||
|
||||
@try {
|
||||
[_invocation invoke];
|
||||
}
|
||||
@catch (NSException * e) {
|
||||
NSLog(@"SPInvocationGrabber's target raised %@:\n\t%@\nInvocation was originally scheduled at:", e.name, e);
|
||||
[self printBacktrace];
|
||||
printf("\n");
|
||||
[e raise];
|
||||
}
|
||||
|
||||
self.invocation = nil;
|
||||
self.object = nil;
|
||||
}
|
||||
|
||||
-(void)saveBacktrace;
|
||||
{
|
||||
void *backtraceFrames[128];
|
||||
frameCount = backtrace(&backtraceFrames[0], 128);
|
||||
frameStrings = backtrace_symbols(&backtraceFrames[0], frameCount);
|
||||
}
|
||||
-(void)printBacktrace;
|
||||
{
|
||||
int x;
|
||||
for(x = 3; x < frameCount; x++) {
|
||||
if(frameStrings[x] == NULL) { break; }
|
||||
printf("%s\n", frameStrings[x]);
|
||||
}
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation NSObject (SPInvocationGrabbing)
|
||||
-(id)grab;
|
||||
{
|
||||
return [[[SPInvocationGrabber alloc] initWithObject:self] autorelease];
|
||||
}
|
||||
-(id)invokeAfter:(NSTimeInterval)delta;
|
||||
{
|
||||
id grabber = [self grab];
|
||||
[NSTimer scheduledTimerWithTimeInterval:delta target:grabber selector:@selector(invoke) userInfo:nil repeats:NO];
|
||||
return grabber;
|
||||
}
|
||||
- (id)nextRunloop;
|
||||
{
|
||||
return [self invokeAfter:0];
|
||||
}
|
||||
-(id)inBackground;
|
||||
{
|
||||
SPInvocationGrabber *grabber = [self grab];
|
||||
grabber.backgroundAfterForward = YES;
|
||||
return grabber;
|
||||
}
|
||||
-(id)onMainAsync:(BOOL)async;
|
||||
{
|
||||
SPInvocationGrabber *grabber = [self grab];
|
||||
grabber.onMainAfterForward = YES;
|
||||
grabber.waitUntilDone = !async;
|
||||
return grabber;
|
||||
}
|
||||
|
||||
@end
|
28
thirdparty/SPMediaKeyTap/SPInvocationGrabbing/gistfile3.m
vendored
Normal file
28
thirdparty/SPMediaKeyTap/SPInvocationGrabbing/gistfile3.m
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
// A
|
||||
+(UIView*)flashAt:(CGRect)r in:(UIView*)parent color:(UIColor*)color;
|
||||
{
|
||||
float duration = 0.5;
|
||||
UIView *flash = [[[UIView alloc] initWithFrame:r] autorelease];
|
||||
flash.backgroundColor = color;
|
||||
[parent addSubview:flash];
|
||||
[[flash invokeAfter:duration+0.1] removeFromSuperview];
|
||||
|
||||
[UIView beginAnimations:@"SPFlash" context:NULL];
|
||||
[UIView setAnimationDuration:duration];
|
||||
flash.alpha = 0.0;
|
||||
[UIView commitAnimations];
|
||||
return flash;
|
||||
}
|
||||
|
||||
// B
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
||||
// Force the animation to happen by calling this method again after a small
|
||||
// delay - see http://blog.instapaper.com/post/53568356
|
||||
[[self nextRunloop] delayedTableViewDidSelectRowAtIndexPath: indexPath];
|
||||
}
|
||||
|
||||
// C
|
||||
[[tableView invokeAfter:0.15] selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionNone];
|
||||
[[tableView invokeAfter:0.30] deselectRowAtIndexPath:indexPath animated:YES];
|
||||
[[tableView invokeAfter:0.45] selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionNone];
|
12
thirdparty/SPMediaKeyTap/SPInvocationGrabbing/gistfile4.m
vendored
Normal file
12
thirdparty/SPMediaKeyTap/SPInvocationGrabbing/gistfile4.m
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
@interface MyClass : NSObject
|
||||
-(BOOL)areTheNewViewersGoneYet:(Duck*)duck;
|
||||
@end
|
||||
...
|
||||
MyClass *myInstance = [[MyClass alloc] init];
|
||||
id invocationGrabber = [[[SPInvocationGrabber alloc] initWithTarget:myInstance] autorelease];
|
||||
|
||||
|
||||
[invocationGrabber areTheNewViewersGoneYet:[Duck yellowDuck]]; // line 9
|
||||
|
||||
|
||||
NSInvocation *invocationForAreTheNewViewersGoneYet = [invocationGrabber invocation];
|
38
thirdparty/SPMediaKeyTap/SPInvocationGrabbing/main.m
vendored
Normal file
38
thirdparty/SPMediaKeyTap/SPInvocationGrabbing/main.m
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "NSObject+SPInvocationGrabbing.h"
|
||||
|
||||
@interface Foo : NSObject {
|
||||
int a;
|
||||
}
|
||||
-(void)startIt;
|
||||
-(void)theBackgroundStuff;
|
||||
-(void)theForegroundStuff;
|
||||
@end
|
||||
|
||||
@implementation Foo
|
||||
-(void)startIt;
|
||||
{
|
||||
NSLog(@"Starting out on the main thread...");
|
||||
a = 3;
|
||||
[[self inBackground] theBackgroundStuff];
|
||||
}
|
||||
-(void)theBackgroundStuff;
|
||||
{
|
||||
NSLog(@"Woah, this is a background thread!");
|
||||
a += 6;
|
||||
[[self onMainAsync:YES] theForegroundStuff];
|
||||
}
|
||||
-(void)theForegroundStuff;
|
||||
{
|
||||
NSLog(@"Hey presto: %d", a);
|
||||
}
|
||||
@end
|
||||
|
||||
int main() {
|
||||
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||
Foo *foo = [Foo new];
|
||||
[foo startIt];
|
||||
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
|
||||
[pool release];
|
||||
return 0;
|
||||
}
|
34
thirdparty/SPMediaKeyTap/SPMediaKeyTap.h
vendored
Normal file
34
thirdparty/SPMediaKeyTap/SPMediaKeyTap.h
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
#include <Cocoa/Cocoa.h>
|
||||
#import <IOKit/hidsystem/ev_keymap.h>
|
||||
#import <Carbon/Carbon.h>
|
||||
|
||||
// http://overooped.com/post/2593597587/mediakeys
|
||||
|
||||
#define SPSystemDefinedEventMediaKeys 8
|
||||
|
||||
@interface SPMediaKeyTap : NSObject {
|
||||
EventHandlerRef _app_switching_ref;
|
||||
EventHandlerRef _app_terminating_ref;
|
||||
CFMachPortRef _eventPort;
|
||||
CFRunLoopSourceRef _eventPortSource;
|
||||
CFRunLoopRef _tapThreadRL;
|
||||
BOOL _shouldInterceptMediaKeyEvents;
|
||||
id _delegate;
|
||||
// The app that is frontmost in this list owns media keys
|
||||
NSMutableArray *_mediaKeyAppList;
|
||||
}
|
||||
+ (NSArray*)defaultMediaKeyUserBundleIdentifiers;
|
||||
|
||||
-(id)initWithDelegate:(id)delegate;
|
||||
|
||||
+(BOOL)usesGlobalMediaKeyTap;
|
||||
-(void)startWatchingMediaKeys;
|
||||
-(void)stopWatchingMediaKeys;
|
||||
-(void)handleAndReleaseMediaKeyEvent:(NSEvent *)event;
|
||||
@end
|
||||
|
||||
@interface NSObject (SPMediaKeyTapDelegate)
|
||||
-(void)mediaKeyTap:(SPMediaKeyTap*)keyTap receivedMediaKeyEvent:(NSEvent*)event;
|
||||
@end
|
||||
|
||||
extern NSString *kMediaKeyUsingBundleIdentifiersDefaultsKey;
|
300
thirdparty/SPMediaKeyTap/SPMediaKeyTap.m
vendored
Normal file
300
thirdparty/SPMediaKeyTap/SPMediaKeyTap.m
vendored
Normal file
@ -0,0 +1,300 @@
|
||||
// Copyright (c) 2010 Spotify AB
|
||||
#import "SPMediaKeyTap.h"
|
||||
#import "SPInvocationGrabbing/NSObject+SPInvocationGrabbing.h" // https://gist.github.com/511181, in submodule
|
||||
|
||||
@interface SPMediaKeyTap ()
|
||||
-(BOOL)shouldInterceptMediaKeyEvents;
|
||||
-(void)setShouldInterceptMediaKeyEvents:(BOOL)newSetting;
|
||||
-(void)startWatchingAppSwitching;
|
||||
-(void)stopWatchingAppSwitching;
|
||||
-(void)eventTapThread;
|
||||
@end
|
||||
static SPMediaKeyTap *singleton = nil;
|
||||
|
||||
static pascal OSStatus appSwitched (EventHandlerCallRef nextHandler, EventRef evt, void* userData);
|
||||
static pascal OSStatus appTerminated (EventHandlerCallRef nextHandler, EventRef evt, void* userData);
|
||||
static CGEventRef tapEventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon);
|
||||
|
||||
|
||||
// Inspired by http://gist.github.com/546311
|
||||
|
||||
@implementation SPMediaKeyTap
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Setup and teardown
|
||||
-(id)initWithDelegate:(id)delegate;
|
||||
{
|
||||
_delegate = delegate;
|
||||
[self startWatchingAppSwitching];
|
||||
singleton = self;
|
||||
_mediaKeyAppList = [NSMutableArray new];
|
||||
return self;
|
||||
}
|
||||
-(void)dealloc;
|
||||
{
|
||||
[self stopWatchingMediaKeys];
|
||||
[self stopWatchingAppSwitching];
|
||||
[_mediaKeyAppList release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
-(void)startWatchingAppSwitching;
|
||||
{
|
||||
// Listen to "app switched" event, so that we don't intercept media keys if we
|
||||
// weren't the last "media key listening" app to be active
|
||||
EventTypeSpec eventType = { kEventClassApplication, kEventAppFrontSwitched };
|
||||
OSStatus err = InstallApplicationEventHandler(NewEventHandlerUPP(appSwitched), 1, &eventType, self, &_app_switching_ref);
|
||||
assert(err == noErr);
|
||||
|
||||
eventType.eventKind = kEventAppTerminated;
|
||||
err = InstallApplicationEventHandler(NewEventHandlerUPP(appTerminated), 1, &eventType, self, &_app_terminating_ref);
|
||||
assert(err == noErr);
|
||||
}
|
||||
-(void)stopWatchingAppSwitching;
|
||||
{
|
||||
if(!_app_switching_ref) return;
|
||||
RemoveEventHandler(_app_switching_ref);
|
||||
_app_switching_ref = NULL;
|
||||
}
|
||||
|
||||
-(void)startWatchingMediaKeys;{
|
||||
[self setShouldInterceptMediaKeyEvents:YES];
|
||||
|
||||
// Add an event tap to intercept the system defined media key events
|
||||
_eventPort = CGEventTapCreate(kCGSessionEventTap,
|
||||
kCGHeadInsertEventTap,
|
||||
kCGEventTapOptionDefault,
|
||||
CGEventMaskBit(NX_SYSDEFINED),
|
||||
tapEventCallback,
|
||||
self);
|
||||
assert(_eventPort != NULL);
|
||||
|
||||
_eventPortSource = CFMachPortCreateRunLoopSource(kCFAllocatorSystemDefault, _eventPort, 0);
|
||||
assert(_eventPortSource != NULL);
|
||||
|
||||
// Let's do this in a separate thread so that a slow app doesn't lag the event tap
|
||||
[NSThread detachNewThreadSelector:@selector(eventTapThread) toTarget:self withObject:nil];
|
||||
}
|
||||
-(void)stopWatchingMediaKeys;
|
||||
{
|
||||
// TODO<nevyn>: Shut down thread, remove event tap port and source
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Accessors
|
||||
|
||||
+(BOOL)usesGlobalMediaKeyTap
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
// breaking in gdb with a key tap inserted sometimes locks up all mouse and keyboard input forever, forcing reboot
|
||||
return NO;
|
||||
#else
|
||||
// XXX(nevyn): MediaKey event tap doesn't work on 10.4, feel free to figure out why if you have the energy.
|
||||
return floor(NSAppKitVersionNumber) >= 949/*NSAppKitVersionNumber10_5*/;
|
||||
#endif
|
||||
}
|
||||
|
||||
+ (NSArray*)defaultMediaKeyUserBundleIdentifiers;
|
||||
{
|
||||
return [NSArray arrayWithObjects:
|
||||
[[NSBundle mainBundle] bundleIdentifier], // your app
|
||||
@"com.spotify.client",
|
||||
@"com.apple.iTunes",
|
||||
@"com.apple.QuickTimePlayerX",
|
||||
@"com.apple.quicktimeplayer",
|
||||
@"com.apple.iWork.Keynote",
|
||||
@"com.apple.iPhoto",
|
||||
@"org.videolan.vlc",
|
||||
@"com.apple.Aperture",
|
||||
@"com.plexsquared.Plex",
|
||||
@"com.soundcloud.desktop",
|
||||
@"com.macromedia.fireworks", // the tap messes up their mouse input
|
||||
nil
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
-(BOOL)shouldInterceptMediaKeyEvents;
|
||||
{
|
||||
BOOL shouldIntercept = NO;
|
||||
@synchronized(self) {
|
||||
shouldIntercept = _shouldInterceptMediaKeyEvents;
|
||||
}
|
||||
return shouldIntercept;
|
||||
}
|
||||
|
||||
-(void)pauseTapOnTapThread:(BOOL)yeahno;
|
||||
{
|
||||
CGEventTapEnable(self->_eventPort, yeahno);
|
||||
}
|
||||
-(void)setShouldInterceptMediaKeyEvents:(BOOL)newSetting;
|
||||
{
|
||||
BOOL oldSetting;
|
||||
@synchronized(self) {
|
||||
oldSetting = _shouldInterceptMediaKeyEvents;
|
||||
_shouldInterceptMediaKeyEvents = newSetting;
|
||||
}
|
||||
if(_tapThreadRL && oldSetting != newSetting) {
|
||||
id grab = [self grab];
|
||||
[grab pauseTapOnTapThread:newSetting];
|
||||
NSTimer *timer = [NSTimer timerWithTimeInterval:0 invocation:[grab invocation] repeats:NO];
|
||||
CFRunLoopAddTimer(_tapThreadRL, (CFRunLoopTimerRef)timer, kCFRunLoopCommonModes);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark
|
||||
#pragma mark -
|
||||
#pragma mark Event tap callbacks
|
||||
|
||||
// Note: method called on background thread
|
||||
|
||||
static CGEventRef tapEventCallback2(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon)
|
||||
{
|
||||
SPMediaKeyTap *self = refcon;
|
||||
|
||||
if(type == kCGEventTapDisabledByTimeout) {
|
||||
NSLog(@"Media key event tap was disabled by timeout");
|
||||
CGEventTapEnable(self->_eventPort, TRUE);
|
||||
return event;
|
||||
} else if(type == kCGEventTapDisabledByUserInput) {
|
||||
// Was disabled manually by -[pauseTapOnTapThread]
|
||||
return event;
|
||||
}
|
||||
NSEvent *nsEvent = nil;
|
||||
@try {
|
||||
nsEvent = [NSEvent eventWithCGEvent:event];
|
||||
}
|
||||
@catch (NSException * e) {
|
||||
NSLog(@"Strange CGEventType: %d: %@", type, e);
|
||||
assert(0);
|
||||
return event;
|
||||
}
|
||||
|
||||
if (type != NX_SYSDEFINED || [nsEvent subtype] != SPSystemDefinedEventMediaKeys)
|
||||
return event;
|
||||
|
||||
int keyCode = (([nsEvent data1] & 0xFFFF0000) >> 16);
|
||||
if (keyCode != NX_KEYTYPE_PLAY && keyCode != NX_KEYTYPE_FAST && keyCode != NX_KEYTYPE_REWIND)
|
||||
return event;
|
||||
|
||||
if (![self shouldInterceptMediaKeyEvents])
|
||||
return event;
|
||||
|
||||
[nsEvent retain]; // matched in handleAndReleaseMediaKeyEvent:
|
||||
[self performSelectorOnMainThread:@selector(handleAndReleaseMediaKeyEvent:) withObject:nsEvent waitUntilDone:NO];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static CGEventRef tapEventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon)
|
||||
{
|
||||
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
||||
CGEventRef ret = tapEventCallback2(proxy, type, event, refcon);
|
||||
[pool drain];
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
// event will have been retained in the other thread
|
||||
-(void)handleAndReleaseMediaKeyEvent:(NSEvent *)event {
|
||||
[event autorelease];
|
||||
|
||||
[_delegate mediaKeyTap:self receivedMediaKeyEvent:event];
|
||||
}
|
||||
|
||||
|
||||
-(void)eventTapThread;
|
||||
{
|
||||
_tapThreadRL = CFRunLoopGetCurrent();
|
||||
CFRunLoopAddSource(_tapThreadRL, _eventPortSource, kCFRunLoopCommonModes);
|
||||
CFRunLoopRun();
|
||||
}
|
||||
|
||||
#pragma mark Task switching callbacks
|
||||
|
||||
NSString *kMediaKeyUsingBundleIdentifiersDefaultsKey = @"SPApplicationsNeedingMediaKeys";
|
||||
|
||||
|
||||
-(void)mediaKeyAppListChanged;
|
||||
{
|
||||
if([_mediaKeyAppList count] == 0) return;
|
||||
|
||||
/*NSLog(@"--");
|
||||
int i = 0;
|
||||
for (NSValue *psnv in _mediaKeyAppList) {
|
||||
ProcessSerialNumber psn; [psnv getValue:&psn];
|
||||
NSDictionary *processInfo = [(id)ProcessInformationCopyDictionary(
|
||||
&psn,
|
||||
kProcessDictionaryIncludeAllInformationMask
|
||||
) autorelease];
|
||||
NSString *bundleIdentifier = [processInfo objectForKey:(id)kCFBundleIdentifierKey];
|
||||
NSLog(@"%d: %@", i++, bundleIdentifier);
|
||||
}*/
|
||||
|
||||
ProcessSerialNumber mySerial, topSerial;
|
||||
GetCurrentProcess(&mySerial);
|
||||
[[_mediaKeyAppList objectAtIndex:0] getValue:&topSerial];
|
||||
|
||||
Boolean same;
|
||||
OSErr err = SameProcess(&mySerial, &topSerial, &same);
|
||||
[self setShouldInterceptMediaKeyEvents:(err == noErr && same)];
|
||||
|
||||
}
|
||||
-(void)appIsNowFrontmost:(ProcessSerialNumber)psn;
|
||||
{
|
||||
NSValue *psnv = [NSValue valueWithBytes:&psn objCType:@encode(ProcessSerialNumber)];
|
||||
|
||||
NSDictionary *processInfo = [(id)ProcessInformationCopyDictionary(
|
||||
&psn,
|
||||
kProcessDictionaryIncludeAllInformationMask
|
||||
) autorelease];
|
||||
NSString *bundleIdentifier = [processInfo objectForKey:(id)kCFBundleIdentifierKey];
|
||||
|
||||
NSArray *whitelistIdentifiers = [[NSUserDefaults standardUserDefaults] arrayForKey:kMediaKeyUsingBundleIdentifiersDefaultsKey];
|
||||
if(![whitelistIdentifiers containsObject:bundleIdentifier]) return;
|
||||
|
||||
[_mediaKeyAppList removeObject:psnv];
|
||||
[_mediaKeyAppList insertObject:psnv atIndex:0];
|
||||
[self mediaKeyAppListChanged];
|
||||
}
|
||||
-(void)appTerminated:(ProcessSerialNumber)psn;
|
||||
{
|
||||
NSValue *psnv = [NSValue valueWithBytes:&psn objCType:@encode(ProcessSerialNumber)];
|
||||
[_mediaKeyAppList removeObject:psnv];
|
||||
[self mediaKeyAppListChanged];
|
||||
}
|
||||
|
||||
static pascal OSStatus appSwitched (EventHandlerCallRef nextHandler, EventRef evt, void* userData)
|
||||
{
|
||||
SPMediaKeyTap *self = (id)userData;
|
||||
|
||||
ProcessSerialNumber newSerial;
|
||||
GetFrontProcess(&newSerial);
|
||||
|
||||
[self appIsNowFrontmost:newSerial];
|
||||
|
||||
return CallNextEventHandler(nextHandler, evt);
|
||||
}
|
||||
|
||||
static pascal OSStatus appTerminated (EventHandlerCallRef nextHandler, EventRef evt, void* userData)
|
||||
{
|
||||
SPMediaKeyTap *self = (id)userData;
|
||||
|
||||
ProcessSerialNumber deadPSN;
|
||||
|
||||
GetEventParameter(
|
||||
evt,
|
||||
kEventParamProcessID,
|
||||
typeProcessSerialNumber,
|
||||
NULL,
|
||||
sizeof(deadPSN),
|
||||
NULL,
|
||||
&deadPSN
|
||||
);
|
||||
|
||||
|
||||
[self appTerminated:deadPSN];
|
||||
return CallNextEventHandler(nextHandler, evt);
|
||||
}
|
||||
|
||||
@end
|
25
thirdparty/SPMediaKeyTap/SPMediaKeyTapDelegate.m
vendored
Normal file
25
thirdparty/SPMediaKeyTap/SPMediaKeyTapDelegate.m
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
-(void)mediaKeyTap:(SPMediaKeyTap*)keyTap receivedMediaKeyEvent:(NSEvent*)event;
|
||||
{
|
||||
assert([event type] == NSSystemDefined && [event subtype] == SPSystemDefinedEventMediaKeys);
|
||||
|
||||
int keyCode = (([event data1] & 0xFFFF0000) >> 16);
|
||||
int keyFlags = ([event data1] & 0x0000FFFF);
|
||||
int keyState = (((keyFlags & 0xFF00) >> 8)) == 0xA;
|
||||
int keyRepeat = (keyFlags & 0x1);
|
||||
|
||||
if (keyState == 1 && windowController != NULL) {
|
||||
|
||||
|
||||
switch (keyCode) {
|
||||
|
||||
case NX_KEYTYPE_PLAY:
|
||||
... return;
|
||||
|
||||
case NX_KEYTYPE_FAST:
|
||||
... return;
|
||||
|
||||
case NX_KEYTYPE_REWIND:
|
||||
... return;
|
||||
}
|
||||
}
|
||||
}
|
2
thirdparty/jreen
vendored
2
thirdparty/jreen
vendored
@ -1 +1 @@
|
||||
Subproject commit 8f995f246637f533feb7124744e113034a32b505
|
||||
Subproject commit 2957d0ff03d9561af8afc4bd3a45947392868875
|
Loading…
x
Reference in New Issue
Block a user