1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-03-13 20:39:57 +01:00

Merge branch 'master' into accounts

Conflicts:
	src/libtomahawk/utils/xspfloader.cpp
	src/libtomahawk/utils/xspfloader.h
	src/tomahawkapp.cpp
	src/tomahawkwindow.h
This commit is contained in:
Leo Franchi 2012-02-27 08:37:40 -05:00
commit f4c92793e6
38 changed files with 356 additions and 40 deletions

View File

@ -1,3 +1,5 @@
Version 0.4.0:
Version 0.3.3:
* Automatically load Super Collection tracks when no official release
information is available.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -135,5 +135,6 @@
<file>data/images/rdio.png</file>
<file>data/images/lastfm-icon.png</file>
<file>data/sql/dbmigrate-27_to_28.sql</file>
<file>data/images/process-stop.png</file>
</qresource>
</RCC>

View File

@ -58,4 +58,7 @@ if (APPLE)
FILE(COPY ${CMAKE_SOURCE_DIR}/admin/mac/sparkle_pub.pem
DESTINATION "${CMAKE_BINARY_DIR}/tomahawk.app/Contents/Resources")
FILE(COPY /usr/bin/SetFile DESTINATION "${CMAKE_BINARY_DIR}/tomahawk.app/Contents/MacOS")
FILE(COPY /usr/bin/GetFileInfo DESTINATION "${CMAKE_BINARY_DIR}/tomahawk.app/Contents/MacOS")
endif (APPLE)

View File

@ -38,6 +38,7 @@ set( libGuiSources
jobview/PipelineStatusItem.cpp
jobview/TransferStatusItem.cpp
jobview/LatchedStatusItem.cpp
jobview/ErrorStatusMessage.cpp
infobar/infobar.cpp
@ -272,6 +273,7 @@ set( libGuiHeaders
jobview/PipelineStatusItem.h
jobview/TransferStatusItem.h
jobview/LatchedStatusItem.h
jobview/ErrorStatusMessage.h
thirdparty/Qocoa/qsearchfield.h
)

View File

@ -590,10 +590,10 @@ AudioEngine::onStateChanged( Phonon::State newState, Phonon::State oldState )
if ( newState == Phonon::ErrorState )
{
stop();
tLog() << "Phonon Error:" << m_mediaObject->errorString() << m_mediaObject->errorType();
emit error( UnknownError );
stop();
return;
}
if ( newState == Phonon::PlayingState )

View File

@ -35,6 +35,8 @@
#include "utils/xspfloader.h"
#include "jobview/JobStatusView.h"
#include "jobview/JobStatusModel.h"
#include "jobview/ErrorStatusMessage.h"
#ifdef QCA2_FOUND
#include "utils/groovesharkparser.h"
#endif //QCA2_FOUND
@ -699,10 +701,18 @@ DropJob::removeDuplicates()
{
bool contains = false;
foreach( const Tomahawk::query_ptr &tmpItem, list )
{
if ( item->album() == tmpItem->album()
&& item->artist() == tmpItem->artist()
&& item->track() == tmpItem->track() )
{
if ( item->playable() && !tmpItem->playable() )
list.replace( list.indexOf( tmpItem ), item );
contains = true;
break;
}
}
if ( !contains )
list.append( item );
}

View File

@ -23,6 +23,8 @@
#include "query.h"
#include "infosystem/infosystem.h"
#include "utils/xspfloader.h"
#include <QObject>
#include <QStringList>
#include <QMimeData>

View File

@ -451,8 +451,15 @@ LastFmPlugin::notInCacheSlot( QHash<QString, QString> criteria, Tomahawk::InfoSy
QString artistName = criteria["artist"];
QString albumName = criteria["album"];
QString imgurl = "http://ws.audioscrobbler.com/2.0/?method=album.imageredirect&artist=%1&album=%2&autocorrect=1&size=large&api_key=7a90f6672a04b809ee309af169f34b8b";
QNetworkRequest req( imgurl.arg( artistName ).arg( albumName ) );
QUrl imgurl( "http://ws.audioscrobbler.com/2.0/" );
imgurl.addQueryItem( "method", "album.imageredirect" );
imgurl.addQueryItem( "artist", artistName );
imgurl.addQueryItem( "album", albumName );
imgurl.addQueryItem( "autocorrect", QString::number( 1 ) );
imgurl.addQueryItem( "size", "large" );
imgurl.addQueryItem( "api_key", "7a90f6672a04b809ee309af169f34b8b" );
QNetworkRequest req( imgurl );
QNetworkReply* reply = TomahawkUtils::nam()->get( req );
reply->setProperty( "requestData", QVariant::fromValue< Tomahawk::InfoSystem::InfoRequestData >( requestData ) );
@ -464,8 +471,14 @@ LastFmPlugin::notInCacheSlot( QHash<QString, QString> criteria, Tomahawk::InfoSy
{
QString artistName = criteria["artist"];
QString imgurl = "http://ws.audioscrobbler.com/2.0/?method=artist.imageredirect&artist=%1&autocorrect=1&size=large&api_key=7a90f6672a04b809ee309af169f34b8b";
QNetworkRequest req( imgurl.arg( artistName ) );
QUrl imgurl( "http://ws.audioscrobbler.com/2.0/" );
imgurl.addQueryItem( "method", "artist.imageredirect" );
imgurl.addQueryItem( "artist", artistName );
imgurl.addQueryItem( "autocorrect", QString::number( 1 ) );
imgurl.addQueryItem( "size", "large" );
imgurl.addQueryItem( "api_key", "7a90f6672a04b809ee309af169f34b8b" );
QNetworkRequest req( imgurl );
QNetworkReply* reply = TomahawkUtils::nam()->get( req );
reply->setProperty( "requestData", QVariant::fromValue< Tomahawk::InfoSystem::InfoRequestData >( requestData ) );

View File

@ -0,0 +1,56 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2012, Leo Franchi <lfranchi@kde.org>
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* 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 "ErrorStatusMessage.h"
#include "utils/tomahawkutils.h"
#include <QTimer>
QPixmap* ErrorStatusMessage::s_pixmap = 0;
ErrorStatusMessage::ErrorStatusMessage( const QString& message, int timeoutSecs )
: JobStatusItem()
, m_message( message )
{
m_timer = new QTimer( this );
m_timer->setInterval( timeoutSecs * 1000 );
m_timer->setSingleShot( true );
connect( m_timer, SIGNAL( timeout() ), this, SIGNAL( finished() ) );
if ( !s_pixmap )
s_pixmap = new QPixmap( RESPATH "images/process-stop.png" );
m_timer->start();
}
QPixmap
ErrorStatusMessage::icon() const
{
Q_ASSERT( s_pixmap );
return *s_pixmap;
}
QString
ErrorStatusMessage::mainText() const
{
return m_message;
}

View File

@ -0,0 +1,48 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2012, Leo Franchi <lfranchi@kde.org>
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* 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 ERRORSTATUSMESSAGE_H
#define ERRORSTATUSMESSAGE_H
#include "JobStatusItem.h"
#include "dllmacro.h"
class QTimer;
class QPixmap;
class DLLEXPORT ErrorStatusMessage : public JobStatusItem
{
Q_OBJECT
public:
explicit ErrorStatusMessage( const QString& errorMessage, int defaultTimeoutSecs = 8 );
QString type() const { return "errormessage"; }
QString rightColumnText() const { return QString(); }
QPixmap icon() const;
QString mainText() const;
bool allowMultiLine() const { return true; }
private:
QString m_message;
QTimer* m_timer;
static QPixmap* s_pixmap;
};
#endif // ERRORSTATUSMESSAGE_H

View File

@ -23,14 +23,16 @@
#include <QPainter>
#include <QApplication>
#include <QListView>
#define ROW_HEIGHT 20
#define ICON_PADDING 1
#define PADDING 2
JobStatusDelegate::JobStatusDelegate( QObject* parent )
: QStyledItemDelegate ( parent )
, m_parentView( qobject_cast< QListView* >( parent ) )
{
Q_ASSERT( m_parentView );
}
JobStatusDelegate::~JobStatusDelegate()
@ -45,6 +47,7 @@ JobStatusDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option,
QStyleOptionViewItemV4 opt = option;
initStyleOption( &opt, index );
QFontMetrics fm( opt.font );
const bool allowMultiLine = index.data( JobStatusModel::AllowMultiLineRole ).toBool();
opt.state &= ~QStyle::State_MouseOver;
QApplication::style()->drawPrimitive( QStyle::PE_PanelItemViewItem, &opt, painter, opt.widget );
@ -52,7 +55,9 @@ JobStatusDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option,
// painter->drawLine( opt.rect.topLeft(), opt.rect.topRight() );
painter->setRenderHint( QPainter::Antialiasing );
const QRect iconRect( ICON_PADDING, ICON_PADDING + opt.rect.y(), ROW_HEIGHT - 2*ICON_PADDING, ROW_HEIGHT - 2*ICON_PADDING );
QRect iconRect( ICON_PADDING, ICON_PADDING + opt.rect.y(), ROW_HEIGHT - 2*ICON_PADDING, ROW_HEIGHT - 2*ICON_PADDING );
if ( allowMultiLine )
iconRect.moveTop( opt.rect.top() + opt.rect.height() / 2 - iconRect.height() / 2);
QPixmap p = index.data( Qt::DecorationRole ).value< QPixmap >();
p = p.scaledToHeight( iconRect.height(), Qt::SmoothTransformation );
painter->drawPixmap( iconRect, p );
@ -71,15 +76,34 @@ JobStatusDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option,
const int mainW = rightEdge - 3*PADDING - iconRect.right();
QString mainText = index.data( Qt::DisplayRole ).toString();
mainText = fm.elidedText( mainText, Qt::ElideRight, mainW );
painter->drawText( QRect( iconRect.right() + 2*PADDING, PADDING + opt.rect.y(), mainW, opt.rect.height() - 2*PADDING ), Qt::AlignLeft | Qt::AlignVCenter, mainText );
QTextOption to( Qt::AlignLeft | Qt::AlignVCenter );
if ( !allowMultiLine )
mainText = fm.elidedText( mainText, Qt::ElideRight, mainW );
else
to.setWrapMode( QTextOption::WrapAtWordBoundaryOrAnywhere );
painter->drawText( QRect( iconRect.right() + 2*PADDING, PADDING + opt.rect.y(), mainW, opt.rect.height() - 2*PADDING ), mainText, to );
}
QSize
JobStatusDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const
{
// return QStyledItemDelegate::sizeHint( option, index );
const int w = QStyledItemDelegate::sizeHint ( option, index ).width();
return QSize( w, ROW_HEIGHT );
const bool allowMultiLine = index.data( JobStatusModel::AllowMultiLineRole ).toBool();
if ( !allowMultiLine )
return QSize( QStyledItemDelegate::sizeHint ( option, index ).width(), ROW_HEIGHT );
else if ( m_cachedMultiLineHeights.contains( index ) )
return QSize( QStyledItemDelegate::sizeHint ( option, index ).width(), m_cachedMultiLineHeights[ index ] );
// Don't elide, but stretch across as many rows as required
QStyleOptionViewItemV4 opt = option;
initStyleOption( &opt, index );
const QString text = index.data( Qt::DisplayRole ).toString();
const int leftEdge = ICON_PADDING + ROW_HEIGHT + 2*PADDING;
const QRect rect = opt.fontMetrics.boundingRect( leftEdge, opt.rect.top(), m_parentView->width() - leftEdge, 200, Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap, text );
m_cachedMultiLineHeights.insert( index, rect.height() + 4*PADDING );
return QSize( QStyledItemDelegate::sizeHint ( option, index ).width(), rect.height() + 4*PADDING );
}

View File

@ -22,6 +22,7 @@
#include <QStyledItemDelegate>
class QPainter;
class QListView;
class JobStatusDelegate : public QStyledItemDelegate
{
@ -33,6 +34,10 @@ public:
virtual void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
virtual QSize sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const;
private:
mutable QHash< QPersistentModelIndex, int > m_cachedMultiLineHeights;
QListView* m_parentView;
};
#endif // JOBSTATUSDELEGATE_H

View File

@ -53,6 +53,7 @@ public:
* and a count will be shown instead.
*/
virtual bool collapseItem() const { return false; }
virtual bool allowMultiLine() const { return false; }
signals:
/// Ask for an update

View File

@ -100,6 +100,8 @@ JobStatusModel::data( const QModelIndex& index, int role ) const
else
return item->rightColumnText();
}
case AllowMultiLineRole:
return item->allowMultiLine();
}
return QVariant();

View File

@ -31,7 +31,8 @@ public:
enum JobRoles {
// DecorationRole is icon
// DisplayRole is main col
RightColumnRole = Qt::UserRole + 1
RightColumnRole = Qt::UserRole + 1,
AllowMultiLineRole = Qt::UserRole + 2
};
explicit JobStatusModel( QObject* parent = 0 );

View File

@ -40,6 +40,7 @@ JobStatusView* JobStatusView::s_instance = 0;
JobStatusView::JobStatusView( AnimatedSplitter* parent )
: AnimatedWidget( parent )
, m_parent( parent )
, m_cachedHeight( -1 )
{
s_instance = this;
@ -56,9 +57,7 @@ JobStatusView::JobStatusView( AnimatedSplitter* parent )
m_view->setFrameShape( QFrame::NoFrame );
m_view->setAttribute( Qt::WA_MacShowFocusRect, 0 );
// new QTreeWidgetItem( m_tree );
m_view->setUniformItemSizes( true );
m_view->setUniformItemSizes( false );
#ifndef Q_WS_WIN
QFont f = font();
@ -86,12 +85,14 @@ JobStatusView::setModel( JobStatusModel* m )
connect( m_view->model(), SIGNAL( rowsInserted( QModelIndex, int, int ) ), this, SLOT( checkCount() ) );
connect( m_view->model(), SIGNAL( rowsRemoved( QModelIndex, int, int ) ), this, SLOT( checkCount() ) );
connect( m_view->model(), SIGNAL( modelReset() ), this, SLOT( checkCount() ) );
}
void
JobStatusView::checkCount()
{
m_cachedHeight = -1;
if ( m_view->model()->rowCount() == 0 && !isHidden() )
emit hideWidget();
else
@ -102,15 +103,21 @@ JobStatusView::checkCount()
QSize
JobStatusView::sizeHint() const
{
if ( m_cachedHeight >= 0 )
return QSize( 0, m_cachedHeight );
unsigned int y = 0;
// y += m_tree->header()->height();
y += m_view->contentsMargins().top() + m_view->contentsMargins().bottom();
if ( m_view->model()->rowCount() )
{
unsigned int rowheight = m_view->sizeHintForRow( 0 );
y += rowheight * m_view->model()->rowCount() + 2;
for ( int i = 0; i < m_view->model()->rowCount(); i++ )
{
y += m_view->sizeHintForRow( i );
}
y += 2; // some padding
}
m_cachedHeight = y;
return QSize( 0, y );
}

View File

@ -56,6 +56,7 @@ private:
QListView* m_view;
JobStatusModel* m_model;
AnimatedSplitter* m_parent;
mutable int m_cachedHeight;
static JobStatusView* s_instance;
};

View File

@ -181,6 +181,7 @@ Tomahawk::EchonestControl::updateWidgets()
input->hide();
m_match = QWeakPointer< QWidget >( match );
m_input = QWeakPointer< QWidget >( input );
m_data.first = m_currentType;
} else if( selectedType() == "Artist Description" ) {
m_currentType = Echonest::DynamicPlaylist::Description;
@ -199,6 +200,7 @@ Tomahawk::EchonestControl::updateWidgets()
input->hide();
m_match = QWeakPointer< QWidget >( match );
m_input = QWeakPointer< QWidget >( input );
m_data.first = m_currentType;
} else if( selectedType() == "User Radio" ) {
m_currentType = Echonest::DynamicPlaylist::SourceCatalog;
@ -246,6 +248,7 @@ Tomahawk::EchonestControl::updateWidgets()
input->hide();
m_match = QWeakPointer< QWidget >( match );
m_input = QWeakPointer< QWidget >( input );
m_data.first = m_currentType;
} else if( selectedType() == "Variety" ) {
m_currentType = Echonest::DynamicPlaylist::Variety;
@ -266,6 +269,7 @@ Tomahawk::EchonestControl::updateWidgets()
input->hide();
m_match = QWeakPointer< QWidget >( match );
m_input = QWeakPointer< QWidget >( input );
m_data.first = m_currentType;
} else if( selectedType() == "Adventurousness" ) {
m_currentType = Echonest::DynamicPlaylist::Adventurousness;
@ -287,6 +291,7 @@ Tomahawk::EchonestControl::updateWidgets()
input->hide();
m_match = QWeakPointer< QWidget >( match );
m_input = QWeakPointer< QWidget >( input );
m_data.first = m_currentType;
} else if( selectedType() == "Tempo" ) {
m_currentType = Echonest::DynamicPlaylist::MinTempo;

View File

@ -27,6 +27,7 @@
#include "dropjob.h"
#include "jobview/JobStatusView.h"
#include "jobview/JobStatusModel.h"
#include "jobview/ErrorStatusMessage.h"
#include "dropjobnotifier.h"
#include "viewmanager.h"
@ -198,6 +199,7 @@ GroovesharkParser::groovesharkLookupFinished()
} else
{
JobStatusView::instance()->model()->addJob( new ErrorStatusMessage( tr( "Error fetching Grooveshark information from the network!" ) ) );
tLog() << "Error in network request to grooveshark for track decoding:" << r->errorString();
}

View File

@ -25,6 +25,7 @@
#include "sourcelist.h"
#include "jobview/JobStatusView.h"
#include "jobview/JobStatusModel.h"
#include "jobview/ErrorStatusMessage.h"
#include <qjson/parser.h>
@ -166,6 +167,7 @@ ItunesParser::itunesResponseLookupFinished()
} else
{
JobStatusView::instance()->model()->addJob( new ErrorStatusMessage( tr( "Error fetching iTunes information from the network!" ) ) );
tLog() << "Error in network request to Itunes for track decoding:" << r->errorString();
}

View File

@ -26,6 +26,7 @@
#include "dropjob.h"
#include "jobview/JobStatusView.h"
#include "jobview/JobStatusModel.h"
#include "jobview/ErrorStatusMessage.h"
#include "dropjobnotifier.h"
#include "viewmanager.h"
#include "sourcelist.h"
@ -189,6 +190,7 @@ RdioParser::rdioReturned()
} else
{
JobStatusView::instance()->model()->addJob( new ErrorStatusMessage( tr( "Error fetching Rdio information from the network!" ) ) );
tLog() << "Error in network request to Rdio for track decoding:" << r->errorString();
}

View File

@ -22,6 +22,9 @@
#include "utils/logger.h"
#include "utils/tomahawkutils.h"
#include "query.h"
#include "jobview/ErrorStatusMessage.h"
#include "jobview/JobStatusModel.h"
#include "jobview/JobStatusView.h"
#include <qjson/parser.h>
@ -78,6 +81,9 @@ ShortenedLinkParser::lookupFinished()
QNetworkReply* r = qobject_cast< QNetworkReply* >( sender() );
Q_ASSERT( r );
if ( r->error() != QNetworkReply::NoError )
JobStatusView::instance()->model()->addJob( new ErrorStatusMessage( tr( "Network error parsing shortened link!" ) ) );
QVariant redir = r->attribute( QNetworkRequest::RedirectionTargetAttribute );
if ( redir.isValid() && !redir.toUrl().isEmpty() )
{

View File

@ -26,6 +26,7 @@
#include "dropjob.h"
#include "jobview/JobStatusView.h"
#include "jobview/JobStatusModel.h"
#include "jobview/ErrorStatusMessage.h"
#include "dropjobnotifier.h"
#include "viewmanager.h"
@ -220,6 +221,7 @@ SpotifyParser::spotifyBrowseFinished()
} else
{
JobStatusView::instance()->model()->addJob( new ErrorStatusMessage( tr( "Error fetching Spotify information from the network!" ) ) );
tLog() << "Error in network request to Spotify for track decoding:" << r->errorString();
}

View File

@ -1,7 +1,7 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
* Copyright 2011-2012, Leo Franchi <lfranchi@kde.org>
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -26,6 +26,12 @@
#include "utils/tomahawkutils.h"
#include "utils/logger.h"
#ifndef ENABLE_HEADLESS
#include "jobview/JobStatusView.h"
#include "jobview/JobStatusModel.h"
#include "jobview/ErrorStatusMessage.h"
#endif
#include "sourcelist.h"
#include "playlist.h"
#include <XspfUpdater.h>
@ -33,6 +39,22 @@
using namespace Tomahawk;
QString
XSPFLoader::errorToString( XSPFErrorCode error )
{
switch ( error )
{
case ParseError:
return tr( "Failed to parse contents of XSPF playlist" );
case InvalidTrackError:
return tr( "Some playlist entries were found without artist and track name, they will be omitted");
case FetchError:
return tr( "Failed to fetch the desired playlist from the network, or the desired file does not exist" );
default:
return QString();
}
}
XSPFLoader::XSPFLoader( bool autoCreate, bool autoUpdate, QObject *parent )
: QObject( parent )
, m_autoCreate( autoCreate )
@ -98,6 +120,9 @@ void
XSPFLoader::reportError()
{
emit error( FetchError );
#ifndef ENABLE_HEADLESS
JobStatusView::instance()->model()->addJob( new ErrorStatusMessage( errorToString( FetchError) ) );
#endif
deleteLater();
}

View File

@ -1,7 +1,7 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
* Copyright 2011-2012, Leo Franchi <lfranchi@kde.org>
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -49,6 +49,8 @@ public:
void setOverrideTitle( const QString& newTitle );
void setAutoResolveTracks( bool autoResolve ) { m_autoResolve = autoResolve; }
static QString errorToString( XSPFErrorCode error );
signals:
void error( XSPFLoader::XSPFErrorCode error );
void ok( const Tomahawk::playlist_ptr& );

View File

@ -22,6 +22,7 @@
#include "utils/logger.h"
#include "tomahawksettings.h"
#include <QCoreApplication>
#include <QProcess>
static QString s_macVolumePath = "/Volumes";
@ -31,9 +32,12 @@ CheckDirModel::CheckDirModel( QWidget* parent )
, m_shownVolumes( false )
{
#ifdef Q_WS_MAC
m_setFilePath = QString( "%1/SetFile" ) .arg( QCoreApplication::applicationDirPath() );
m_getFileInfoPath = QString( "%1/GetFileInfo" ).arg( QCoreApplication::applicationDirPath() );
QProcess* checkVolumeVisible = new QProcess( this );
connect( checkVolumeVisible, SIGNAL( readyReadStandardOutput() ), this, SLOT( getFileInfoResult() ) );
checkVolumeVisible->start( "GetFileInfo", QStringList() << "-aV" << s_macVolumePath );
checkVolumeVisible->start( m_getFileInfoPath, QStringList() << "-aV" << s_macVolumePath );
#endif
}
@ -42,7 +46,7 @@ CheckDirModel::~CheckDirModel()
#ifdef Q_WS_MAC
// reset to previous state
if ( m_shownVolumes )
QProcess::startDetached( QString( "SetFile -a V %1" ).arg( s_macVolumePath ) );
QProcess::startDetached( QString( "%1 -a V %2" ).arg( m_setFilePath).arg( s_macVolumePath ) );
#endif
}
@ -60,7 +64,7 @@ CheckDirModel::getFileInfoResult()
// Remove the hidden flag for the /Volumnes folder so all mount points are visible in the default (Q)FileSystemModel
QProcess* p = new QProcess( this );
connect( p, SIGNAL( finished( int, QProcess::ExitStatus ) ), this, SLOT( volumeShowFinished() ) );
p->start( QString( "SetFile -a v %1" ).arg( s_macVolumePath ) );
p->start( QString( "%1 -a v %2" ).arg( m_setFilePath ).arg( s_macVolumePath ) );
m_shownVolumes = true;
}

View File

@ -51,6 +51,8 @@ private:
QHash<QPersistentModelIndex, Qt::CheckState> m_checkTable;
bool m_shownVolumes;
QString m_setFilePath;
QString m_getFileInfoPath;
};

View File

@ -1,6 +1,7 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
* Copyright 2012 Leo Franchi <lfranchi@kde.org>
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -112,6 +113,20 @@ SearchWidget::changeEvent( QEvent* e )
}
Tomahawk::playlistinterface_ptr
SearchWidget::playlistInterface() const
{
return ui->resultsView->playlistInterface();
}
bool
SearchWidget::jumpToCurrentTrack()
{
return ui->resultsView->jumpToCurrentTrack();
}
void
SearchWidget::onResultsFound( const QList<Tomahawk::result_ptr>& results )
{

View File

@ -1,6 +1,7 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
* Copyright 2012 Leo Franchi <lfranchi@kde.org>
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -46,7 +47,7 @@ public:
~SearchWidget();
virtual QWidget* widget() { return this; }
virtual Tomahawk::playlistinterface_ptr playlistInterface() const { return Tomahawk::playlistinterface_ptr(); }
virtual Tomahawk::playlistinterface_ptr playlistInterface() const;
virtual bool isTemporaryPage() const { return true; }
virtual QString title() const { return QString( tr( "Search: %1" ) ).arg( m_search ); }
@ -55,7 +56,7 @@ public:
virtual bool showStatsBar() const { return false; }
virtual bool jumpToCurrentTrack() { return false; }
virtual bool jumpToCurrentTrack();
protected:
void changeEvent( QEvent* e );

View File

@ -319,11 +319,14 @@ TomahawkApp::~TomahawkApp()
delete AtticaManager::instance();
#endif
delete Pipeline::instance();
if ( !m_database.isNull() )
delete m_database.data();
delete Pipeline::instance();
if ( !m_infoSystem.isNull() )
delete m_infoSystem.data();
tLog() << "Finished shutdown.";
}

View File

@ -58,6 +58,8 @@ TomahawkTrayIcon::TomahawkTrayIcon( QObject* parent )
m_showWindowAction = m_contextMenu->addAction( tr( "Hide Tomahawk Window" ) );
m_showWindowAction->setData( true );
connect( m_showWindowAction, SIGNAL( triggered() ), this, SLOT( showWindow() ) );
connect( m_contextMenu, SIGNAL( aboutToShow() ), this, SLOT( menuAboutToShow() ) );
#endif
m_contextMenu->addSeparator();
@ -118,6 +120,16 @@ TomahawkTrayIcon::showWindow()
}
void
TomahawkTrayIcon::menuAboutToShow()
{
// When using Cmd-H on mac to hide a window, it is an OS-level hide that is different from QWidget::hide().
// Qt returns isVisible() == true for windows that are hidden with Cmd-H, which is weird. isActiveWindow() returns
// the proper information though.
setShowHideWindow( APP->mainWindow()->isActiveWindow() );
}
void
TomahawkTrayIcon::setResult( const Tomahawk::result_ptr& result )
{

View File

@ -46,6 +46,7 @@ private slots:
void enablePlay();
void enablePause();
void menuAboutToShow();
private:
void refreshToolTip();
~TomahawkTrayIcon();

View File

@ -1,7 +1,7 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
* Copyright 2010-2012, Leo Franchi <lfranchi@kde.org>
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -58,6 +58,8 @@
#include "tomahawksettings.h"
#include "sourcelist.h"
#include "jobview/JobStatusView.h"
#include "jobview/JobStatusModel.h"
#include "jobview/ErrorStatusMessage.h"
#include "tomahawktrayicon.h"
#include "scanmanager.h"
#include "tomahawkapp.h"
@ -80,6 +82,7 @@ TomahawkWindow::TomahawkWindow( QWidget* parent )
, m_searchWidget( 0 )
, m_audioControls( new AudioControls( this ) )
, m_trayIcon( new TomahawkTrayIcon( this ) )
, m_audioRetryCounter( 0 )
{
setWindowIcon( QIcon( RESPATH "icons/tomahawk-icon-128x128.png" ) );
@ -570,11 +573,17 @@ TomahawkWindow::onXSPFError( XSPFLoader::XSPFErrorCode error )
void
TomahawkWindow::onAudioEngineError( AudioEngine::AudioErrorCode /* error */ )
{
QString msg;
#ifdef Q_WS_X11
QMessageBox::warning( this, tr( "Playback Error" ), tr( "Sorry, there is a problem accessing your audio device. Make sure you have a suitable Phonon backend and required plugins installed." ), QMessageBox::Ok );
msg = tr( "Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed." );
#else
QMessageBox::warning( this, tr( "Playback Error" ), tr( "Sorry, there is a problem accessing your audio device." ), QMessageBox::Ok );
msg = tr( "Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped." );
#endif
JobStatusView::instance()->model()->addJob( new ErrorStatusMessage( msg, 15 ) );
if ( m_audioRetryCounter < 3 )
AudioEngine::instance()->play();
m_audioRetryCounter++;
}
@ -654,6 +663,7 @@ TomahawkWindow::playlistCreateDialogFinished( int ret )
void
TomahawkWindow::audioStarted()
{
m_audioRetryCounter = 0;
ui->actionPlay->setText( tr( "Pause" ) );
}

View File

@ -1,7 +1,7 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
* Copyright 2010-2011, Leo Franchi <lfranchi@kde.org>
* Copyright 2010-2012, Leo Franchi <lfranchi@kde.org>
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -145,6 +145,7 @@ private:
Tomahawk::result_ptr m_currentTrack;
QString m_windowTitle;
int m_audioRetryCounter;
};
#endif // TOMAHAWKWINDOW_H

View File

@ -88,11 +88,11 @@
}
-(void)printBacktrace;
{
int x;
for(x = 3; x < frameCount; x++) {
if(frameStrings[x] == NULL) { break; }
printf("%s\n", frameStrings[x]);
}
int x;
for(x = 3; x < frameCount; x++) {
if(frameStrings[x] == NULL) { break; }
printf("%s\n", frameStrings[x]);
}
}
@end

View File

@ -31,4 +31,13 @@
-(void)mediaKeyTap:(SPMediaKeyTap*)keyTap receivedMediaKeyEvent:(NSEvent*)event;
@end
extern NSString *kMediaKeyUsingBundleIdentifiersDefaultsKey;
#ifdef __cplusplus
extern "C" {
#endif
extern NSString *kMediaKeyUsingBundleIdentifiersDefaultsKey;
extern NSString *kIgnoreMediaKeysDefaultsKey;
#ifdef __cplusplus
}
#endif

View File

@ -28,6 +28,9 @@ static CGEventRef tapEventCallback(CGEventTapProxy proxy, CGEventType type, CGEv
[self startWatchingAppSwitching];
singleton = self;
_mediaKeyAppList = [NSMutableArray new];
_tapThreadRL=nil;
_eventPort=nil;
_eventPortSource=nil;
return self;
}
-(void)dealloc;
@ -58,6 +61,9 @@ static CGEventRef tapEventCallback(CGEventTapProxy proxy, CGEventType type, CGEv
}
-(void)startWatchingMediaKeys;{
// Prevent having multiple mediaKeys threads
[self stopWatchingMediaKeys];
[self setShouldInterceptMediaKeyEvents:YES];
// Add an event tap to intercept the system defined media key events
@ -78,6 +84,22 @@ static CGEventRef tapEventCallback(CGEventTapProxy proxy, CGEventType type, CGEv
-(void)stopWatchingMediaKeys;
{
// TODO<nevyn>: Shut down thread, remove event tap port and source
if(_tapThreadRL){
CFRunLoopStop(_tapThreadRL);
_tapThreadRL=nil;
}
if(_eventPort){
CFMachPortInvalidate(_eventPort);
CFRelease(_eventPort);
_eventPort=nil;
}
if(_eventPortSource){
CFRelease(_eventPortSource);
_eventPortSource=nil;
}
}
#pragma mark -
@ -90,7 +112,9 @@ static CGEventRef tapEventCallback(CGEventTapProxy proxy, CGEventType type, CGEv
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*/;
return
![[NSUserDefaults standardUserDefaults] boolForKey:kIgnoreMediaKeysDefaultsKey]
&& floor(NSAppKitVersionNumber) >= 949/*NSAppKitVersionNumber10_5*/;
#endif
}
@ -108,6 +132,14 @@ static CGEventRef tapEventCallback(CGEventTapProxy proxy, CGEventType type, CGEv
@"com.apple.Aperture",
@"com.plexsquared.Plex",
@"com.soundcloud.desktop",
@"org.niltsh.MPlayerX",
@"com.ilabs.PandorasHelper",
@"com.mahasoftware.pandabar",
@"com.bitcartel.pandorajam",
@"org.clementine-player.clementine",
@"fm.last.Last.fm",
@"com.beatport.BeatportPro",
@"com.Timenut.SongKey",
@"com.macromedia.fireworks", // the tap messes up their mouse input
nil
];
@ -213,6 +245,8 @@ static CGEventRef tapEventCallback(CGEventTapProxy proxy, CGEventType type, CGEv
#pragma mark Task switching callbacks
NSString *kMediaKeyUsingBundleIdentifiersDefaultsKey = @"SPApplicationsNeedingMediaKeys";
NSString *kIgnoreMediaKeysDefaultsKey = @"SPIgnoreMediaKeys";
-(void)mediaKeyAppListChanged;