diff --git a/CMakeLists.txt b/CMakeLists.txt
index 71c62fdea..7cd00c3c3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -8,10 +8,10 @@ ENDIF( ${CMAKE_VERSION} VERSION_GREATER 2.8.3 )
###
### Tomahawk application info
###
-SET( ORGANIZATION_NAME "Tomahawk" )
-SET( ORGANIZATION_DOMAIN "tomahawk-player.org" )
-SET( APPLICATION_NAME "Tomahawk" )
-SET( VERSION "0.0.3" )
+SET( TOMAHAWK_ORGANIZATION_NAME "Tomahawk" )
+SET( TOMAHAWK_ORGANIZATION_DOMAIN "tomahawk-player.org" )
+SET( TOMAHAWK_APPLICATION_NAME "Tomahawk" )
+SET( TOMAHAWK_VERSION "0.0.3" )
# set paths
@@ -50,6 +50,28 @@ macro_log_feature(QJSON_FOUND "QJson" "Qt library that maps JSON data to QVarian
macro_optional_find_package(Taglib 1.6.0)
macro_log_feature(TAGLIB_FOUND "TagLib" "Audio Meta-Data Library" "http://developer.kde.org/~wheeler/taglib.html" TRUE "" "taglib is needed for reading meta data from audio files")
+# this installs headers and such and should really be handled in a separate package by packagers
+IF( INTERNAL_JREEN )
+ ADD_SUBDIRECTORY( thirdparty/jreen )
+ SET( LIBJREEN_INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR}/thirdparty/jreen/include )
+
+ IF( UNIX AND NOT APPLE )
+ SET( LIBJREEN_LIBRARY ${CMAKE_CURRENT_BINARY_DIR}/thirdparty/jreen/libjreen.so )
+ ENDIF( UNIX AND NOT APPLE )
+ IF( APPLE )
+ SET( LIBJREEN_LIBRARY ${CMAKE_CURRENT_BINARY_DIR}/thirdparty/jreen/libjreen.dylib )
+ ENDIF( APPLE )
+ IF( WIN32 )
+ SET( LIBJREEN_LIBRARY ${CMAKE_CURRENT_BINARY_DIR}/thirdparty/jreen/libjreen.dll )
+ ENDIF( WIN32 )
+
+ SET( LIBJREEN_FOUND true )
+ MESSAGE(STATUS "INTERNAL libjreen: ${LIBJREEN_INCLUDE_DIR}, ${LIBJREEN_LIBRARY}")
+ELSE( INTERNAL_JREEN )
+ macro_optional_find_package(Jreen)
+ENDIF( INTERNAL_JREEN )
+macro_log_feature(LIBJREEN_FOUND "Jreen" "Qt XMPP Library" "http://gitorious.org/jreen/jreen" FALSE "" "Jreen is needed for the Jabber SIP plugin. \n\n Use -DINTERNAL_JREEN=ON to build the git submodule inside Tomahawk \n Be aware this installs a full jreen with headers and everything!")
+
# we need pthreads too
find_package(Threads)
@@ -65,32 +87,6 @@ ENDIF()
include( CheckTagLibFileName )
check_taglib_filename( COMPLEX_TAGLIB_FILENAME )
-# optional
-IF( ENABLE_JREEN )
- macro_optional_find_package(Jreen)
- IF( LIBJREEN_FOUND )
- macro_log_feature(JREEN_FOUND "Jreen" "Qt XMPP library" "http://gitorious.org/jreen" FALSE "" "Jreen is needed for the alternative/new Jabber SIP plugin. Built automatically inside Tomahawk, if not installed systemwide and ENABLE_JREEN is true")
- ELSE( LIBJREEN_FOUND )
- SET( OLD_C_FLAGS ${CMAKE_C_FLAGS} )
- SET( CMAKE_C_FLAGS ${CLEAN_C_FLAGS} )
- ADD_SUBDIRECTORY( thirdparty/jreen )
- SET( LIBJREEN_INCLUDE_DIR ${CMAKE_CURRENT_BINARY_DIR}/thirdparty/jreen/include )
- IF( UNIX AND NOT APPLE )
- SET( LIBJREEN_LIBRARY ${CMAKE_CURRENT_BINARY_DIR}/thirdparty/jreen/libjreen.so )
- ENDIF( UNIX AND NOT APPLE )
- IF( WIN32 )
- SET( LIBJREEN_LIBRARY ${CMAKE_CURRENT_BINARY_DIR}/thirdparty/jreen/libjreen.dll )
- ENDIF( WIN32 )
- SET( LIBJREEN_FOUND true )
- MESSAGE(STATUS "Internal libjreen: ${LIBJREEN_INCLUDE_DIR}, ${LIBJREEN_LIBRARY}")
- SET( CMAKE_C_FLAGS ${OLD_C_FLAGS} )
- ENDIF( LIBJREEN_FOUND )
-ELSE( LIBJREEN_FOUND )
- macro_optional_find_package(Gloox 1.0)
- macro_log_feature(GLOOX_FOUND "Gloox" "A portable high-level Jabber/XMPP library for C++" "http://camaya.net/gloox" FALSE "" "Gloox is needed for the Jabber SIP plugin and the XMPP-Bot")
-
-ENDIF( ENABLE_JREEN )
-
IF( WIN32 )
find_library(QTSPARKLE_LIBRARIES qtsparkle)
ENDIF( WIN32 )
diff --git a/CMakeModules/FindJreen.cmake b/CMakeModules/FindJreen.cmake
index 301eb24e7..9174ca65a 100644
--- a/CMakeModules/FindJreen.cmake
+++ b/CMakeModules/FindJreen.cmake
@@ -6,15 +6,15 @@
# LIBJREEN_FOUND, whether libjreen was found
-find_path(LIBJREEN_INCLUDE_DIR NAMES jreen.h
+find_path(LIBJREEN_INCLUDE_DIR NAMES jreen/jreen.h
HINTS
~/usr/include
/opt/local/include
/usr/include
/usr/local/include
/opt/kde4/include
+ ${CMAKE_INSTALL_PREFIX}/include
${KDE4_INCLUDE_DIR}
- PATH_SUFFIXES jreen
)
find_library( LIBJREEN_LIBRARY NAMES jreen
@@ -25,6 +25,8 @@ find_library( LIBJREEN_LIBRARY NAMES jreen
/usr/lib64
/usr/local/lib
/opt/kde4/lib
+ ${CMAKE_INSTALL_PREFIX}/lib
+ ${CMAKE_INSTALL_PREFIX}/lib64
${KDE4_LIB_DIR}
)
@@ -33,7 +35,7 @@ if(LIBJREEN_INCLUDE_DIR AND LIBJREEN_LIBRARY)
set(LIBJREEN_FOUND TRUE)
message(STATUS "Found libjreen: ${LIBJREEN_INCLUDE_DIR}, ${LIBJREEN_LIBRARY}")
else(LIBJREEN_INCLUDE_DIR AND LIBJREEN_LIBRARY)
- set(LIBJREEN_FOUND FALSE)
+ set(LIBJREEN_FOUND FALSE)
if (LIBJREEN_FIND_REQUIRED)
message(FATAL_ERROR "Could NOT find required package libjreen")
endif(LIBJREEN_FIND_REQUIRED)
diff --git a/ChangeLog b/ChangeLog
index f33fe5ebf..8393fc358 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,8 @@
Version 0.1.0:
- * You can now browse and play collections in a tree-view.
+ * Resolvers can now be enabled and disabled, and some can be configured
+ directly in Tomahawk.
+ * Browse and play collections in our snappy tree-view, which also shows
+ images for artists and albums.
* Watch folders for changes and automatically update your collection. This
is on by default; you can turn it off on the Local Music tab in the
settings dialog. Note that this triggers only on files or folders being
@@ -8,6 +11,7 @@ Version 0.1.0:
music collection.
Version 0.0.4:
+ * Fixed crash that could occur when playing a track from a browser.
* Fixed a crash situation caused by sources going on- or offline.
Version 0.0.3:
diff --git a/README b/README
index ca1241e92..c0b39389c 100644
--- a/README
+++ b/README
@@ -1,81 +1,23 @@
-Quickstart on Ubuntu
---------------------
-
- $ sudo apt-get install build-essential cmake libtag1c2a libtag1-dev libqt4-dev libqt4-sql-sqlite \
- libboost-dev zlib1g-dev libgnutls-dev pkg-config
-
-
-Gloox 1.0 (XMPP library)
-------------------------
- On Ubuntu 10.10 (and higher):
- $ sudo apt-get install libgloox-dev
-
- Otherwise see: http://camaya.net/glooxdownload
- You need to build gloox 1.0 from source, Ubuntu 10.04 only packages version 0.9.
-
- Download and unpack tarball:
- $ ./configure --without-openssl --with-gnutls --without-libidn --with-zlib --without-examples --without-tests
- $ CXXFLAGS=-fPIC make
- $ sudo make install
-
-QJson (Qt JSON library)
------------------------
- On Ubuntu 10.04 (and higher):
- $ sudo apt-get install libqjson-dev
-
- Otherwise see: http://sourceforge.net/projects/qjson/files/ (developed using version 0.7.1)
-
- Download and unpack tarball:
- $ ./configure && make
- $ sudo make install
-
-libEchonest 1.1.4
----------------
- See: http://projects.kde.org/projects/playground/libs/libechonest/
-
- Download and unpack tarball:
- $ mkdir build && cd build
- $ cmake ..
- $ make
- $ sudo make install
-
-CLucene 0.9.23
----------------
- See: http://clucene.sourceforge.net/download.shtml
-
- Clone from git and build CLucene:
- $ git clone git://clucene.git.sourceforge.net/gitroot/clucene/clucene
- $ cd clucene && mkdir build && cd build
- $ cmake ..
- $ make
- $ sudo make install
-
-
-Quickstart on OS X
+Compiling Tomahawk
------------------
- Install homebrew
- $ ruby -e "$(curl -fsSL https://gist.github.com/raw/323731/install_homebrew.rb)"
- $ brew install cmake qt qjson gloox taglib boost
-
- Install libEchnoest & CLucene as per the above instructions.
-
- If liblastfm gives problems, do the below:
- $ brew edit liblastfm
- Change the url to https://github.com/davidsansome/liblastfm/tarball/0.3.1
- $ brew install liblastfm
- Copy the md5 hash it returns.
- $ brew edit liblastfm
- Replace the md5 hash with the new one you copied.
- $ brew install liblastfm
-
-
-Now compile Tomahawk
---------------------
$ mkdir build && cd build
$ cmake ..
$ make
+
+ Start the application on Linux:
$ ./tomahawk
+ Start the application on OS X:
+ $ open tomahawk.app
+
+
+Detailed building instructions for Ubuntu
+-----------------------------------------
+ See: http://wiki.tomahawk-player.org/mediawiki/index.php/Building_Ubuntu_Binary_on_Maverick_(10.10)
+
+Detailed building instructions for OS X
+---------------------------------------
+ See: http://wiki.tomahawk-player.org/mediawiki/index.php/Building_OS_X_Application_Bundle_on_Snow_Leopard_(10.6)
Dependencies
@@ -84,7 +26,7 @@ Dependencies
CMake 2.8.0 http://www.cmake.org/
Qt 4.7.0 http://qt.nokia.com/
QJson 0.7.1 http://qjson.sourceforge.net/
- Gloox 1.0 (0.9.x will fail) http://camaya.net/gloox/
+ Gloox 1.0 http://camaya.net/gloox/
SQLite 3.6.22 http://www.sqlite.org/
TagLib 1.6.2 http://developer.kde.org/~wheeler/taglib.html
Boost 1.3x http://www.boost.org/
@@ -96,23 +38,4 @@ Dependencies
MiniUPnP http://miniupnp.free.fr/
liblastfm 0.4.0 http://github.com/jonocole/liblastfm/
-
-To build the app:
------------------
- $ mkdir build && cd build
- $ cmake ..
- $ make
-
-To run the app:
----------------
- Only run the next two commands if you installed any of the dependencies from source on Linux.
- $ export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
- $ sudo ldconfig -v
-
- Start the application on Linux:
- $ ./tomahawk
-
- Start the application on OS X:
- $ open tomahawk.app
-
Enjoy!
diff --git a/data/sql/dbmigrate-22_to_23.sql b/data/sql/dbmigrate-22_to_23.sql
new file mode 100644
index 000000000..0ee92dd21
--- /dev/null
+++ b/data/sql/dbmigrate-22_to_23.sql
@@ -0,0 +1,11 @@
+-- Script to migate from db version 22 to 23.
+-- Only change in this version is that playlists gained a createdOn date.
+-- Set all playlists to created to now.
+--
+-- Separate each command with %%
+
+ALTER TABLE playlist ADD COLUMN createdOn INTEGER NOT NULL DEFAULT 0;
+
+UPDATE playlist SET createdOn = strftime( '%s','now' );
+
+UPDATE settings SET v = '23' WHERE k == 'schema_version';
diff --git a/resources.qrc b/resources.qrc
index 9996e5cb0..7442790aa 100644
--- a/resources.qrc
+++ b/resources.qrc
@@ -88,5 +88,6 @@
./data/www/auth.html
./data/www/auth.na.html
./data/www/tomahawk_banner_small.png
+./data/sql/dbmigrate-22_to_23.sql
diff --git a/src/audiocontrols.cpp b/src/audiocontrols.cpp
index 32fd58ca7..9fe6eb428 100644
--- a/src/audiocontrols.cpp
+++ b/src/audiocontrols.cpp
@@ -213,13 +213,13 @@ AudioControls::onPlaybackStarted( const Tomahawk::result_ptr& result )
onPlaybackLoading( result );
- Tomahawk::InfoSystem::InfoCustomData trackInfo;
- trackInfo["artist"] = QVariant::fromValue< QString >( result->artist()->name() );
- trackInfo["album"] = QVariant::fromValue< QString >( result->album()->name() );
+ Tomahawk::InfoSystem::InfoCriteriaHash trackInfo;
+ trackInfo["artist"] = result->artist()->name();
+ trackInfo["album"] = result->album()->name();
Tomahawk::InfoSystem::InfoSystem::instance()->getInfo(
s_acInfoIdentifier, Tomahawk::InfoSystem::InfoAlbumCoverArt,
- QVariant::fromValue< Tomahawk::InfoSystem::InfoCustomData >( trackInfo ), Tomahawk::InfoSystem::InfoCustomData() );
+ QVariant::fromValue< Tomahawk::InfoSystem::InfoCriteriaHash >( trackInfo ), Tomahawk::InfoSystem::InfoCustomData() );
}
diff --git a/src/config.h.in b/src/config.h.in
index f8246a54d..7ac3931a2 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -1,14 +1,15 @@
#ifndef CONFIG_H_IN
#define CONFIG_H_IN
-#cmakedefine ORGANIZATION_NAME "${ORGANIZATION_NAME}"
-#cmakedefine ORGANIZATION_DOMAIN "${ORGANIZATION_DOMAIN}"
-#cmakedefine APPLICATION_NAME "${APPLICATION_NAME}"
-#cmakedefine VERSION "${VERSION}"
+#cmakedefine TOMAHAWK_ORGANIZATION_NAME "${TOMAHAWK_ORGANIZATION_NAME}"
+#cmakedefine TOMAHAWK_ORGANIZATION_DOMAIN "${TOMAHAWK_ORGANIZATION_DOMAIN}"
+#cmakedefine TOMAHAWK_APPLICATION_NAME "${TOMAHAWK_APPLICATION_NAME}"
+#cmakedefine TOMAHAWK_VERSION "${TOMAHAWK_VERSION}"
#cmakedefine DEBUG_BUILD
#define CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}"
+#define CMAKE_SYSTEM "${CMAKE_SYSTEM}"
#cmakedefine SNOW_LEOPARD
#cmakedefine LEOPARD
diff --git a/src/libtomahawk/database/databasecollection.cpp b/src/libtomahawk/database/databasecollection.cpp
index 23e36584d..bbcf6da79 100644
--- a/src/libtomahawk/database/databasecollection.cpp
+++ b/src/libtomahawk/database/databasecollection.cpp
@@ -143,11 +143,12 @@ void DatabaseCollection::dynamicPlaylistCreated( const source_ptr& source, const
data[1].toString(), //title
data[2].toString(), //info
data[3].toString(), //creator
- data[4].toString(), // dynamic type
- static_cast(data[5].toInt()), // dynamic mode
- data[6].toBool(), //shared
- data[7].toInt(), //lastmod
- data[8].toString() ) ); //GUID
+ data[4].toUInt(), // createdOn
+ data[5].toString(), // dynamic type
+ static_cast(data[6].toInt()), // dynamic mode
+ data[7].toBool(), //shared
+ data[8].toInt(), //lastmod
+ data[9].toString() ) ); //GUID
addDynamicPlaylist( p );
}
diff --git a/src/libtomahawk/database/databasecommand_createdynamicplaylist.cpp b/src/libtomahawk/database/databasecommand_createdynamicplaylist.cpp
index f432f3a25..31b675119 100644
--- a/src/libtomahawk/database/databasecommand_createdynamicplaylist.cpp
+++ b/src/libtomahawk/database/databasecommand_createdynamicplaylist.cpp
@@ -1,5 +1,5 @@
/* === This file is part of Tomahawk Player - ===
- *
+ *
* Copyright 2010-2011, Christian Muehlhaeuser
*
* Tomahawk is free software: you can redistribute it and/or modify
@@ -53,15 +53,15 @@ DatabaseCommand_CreateDynamicPlaylist::exec( DatabaseImpl* lib )
qDebug() << Q_FUNC_INFO;
Q_ASSERT( !( m_playlist.isNull() && m_v.isNull() ) );
Q_ASSERT( !source().isNull() );
-
+
DatabaseCommand_CreatePlaylist::createPlaylist( lib, true );
qDebug() << "Created normal playlist, now creating additional dynamic info!";
-
+
TomahawkSqlQuery cre = lib->newquery();
cre.prepare( "INSERT INTO dynamic_playlist( guid, pltype, plmode ) "
"VALUES( ?, ?, ? )" );
-
+
if( m_playlist.isNull() ) {
QVariantMap m = m_v.toMap();
cre.addBindValue( m.value( "guid" ) );
@@ -73,22 +73,6 @@ DatabaseCommand_CreateDynamicPlaylist::exec( DatabaseImpl* lib )
cre.addBindValue( m_playlist->mode() );
}
cre.exec();
-
- // save the controls -- wait, no controls in a new playlist :P
-// cre = lib->newquery();
-// cre.prepare( "INSERT INTO dynamic_playlist_controls( id, selectedType, match, input) "
-// "VALUES( :id, :selectedType, :match, :input )" );
-// foreach( const dyncontrol_ptr& control, m_playlist->generator()->controls() ) {
-//
-// cre.bindValue( ":id", control->id() );
-// cre.bindValue( ":selectedType", control->selectedType() );
-// cre.bindValue( ":match", control->match() );
-// cre.bindValue( ":input", control->input() );
-//
-// qDebug() << "CREATE DYNPLAYLIST CONTROL:" << cre.boundValues();
-//
-// cre.exec();
-// }
}
@@ -101,10 +85,10 @@ DatabaseCommand_CreateDynamicPlaylist::postCommitHook()
qDebug() << "Source has gone offline, not emitting to GUI.";
return;
}
-
+
if( report() == false )
return;
-
+
qDebug() << Q_FUNC_INFO << "..reporting..";
if( m_playlist.isNull() ) {
source_ptr src = source();
diff --git a/src/libtomahawk/database/databasecommand_createplaylist.cpp b/src/libtomahawk/database/databasecommand_createplaylist.cpp
index b5bd2ccc2..9a9f32697 100644
--- a/src/libtomahawk/database/databasecommand_createplaylist.cpp
+++ b/src/libtomahawk/database/databasecommand_createplaylist.cpp
@@ -1,5 +1,5 @@
/* === This file is part of Tomahawk Player - ===
- *
+ *
* Copyright 2010-2011, Christian Muehlhaeuser
*
* Tomahawk is free software: you can redistribute it and/or modify
@@ -75,25 +75,37 @@ DatabaseCommand_CreatePlaylist::postCommitHook()
} else {
m_playlist->reportCreated( m_playlist );
}
-
+
if( source()->isLocal() )
Servent::instance()->triggerDBSync();
}
-void
+void
DatabaseCommand_CreatePlaylist::createPlaylist( DatabaseImpl* lib, bool dynamic)
{
qDebug() << Q_FUNC_INFO;
Q_ASSERT( !( m_playlist.isNull() && m_v.isNull() ) );
Q_ASSERT( !source().isNull() );
-
+
+ uint now = 0;
+ if( m_playlist.isNull() )
+ {
+ now = m_v.toMap()[ "createdon" ].toUInt();
+ }
+ else
+ {
+ now = QDateTime::currentDateTime().toTime_t();
+ m_playlist->setCreatedOn( now );
+ }
+
TomahawkSqlQuery cre = lib->newquery();
- cre.prepare( "INSERT INTO playlist( guid, source, shared, title, info, creator, lastmodified, dynplaylist) "
- "VALUES( :guid, :source, :shared, :title, :info, :creator, :lastmodified, :dynplaylist )" );
-
+ cre.prepare( "INSERT INTO playlist( guid, source, shared, title, info, creator, lastmodified, dynplaylist, createdOn) "
+ "VALUES( :guid, :source, :shared, :title, :info, :creator, :lastmodified, :dynplaylist, :createdOn )" );
+
cre.bindValue( ":source", source()->isLocal() ? QVariant(QVariant::Int) : source()->id() );
cre.bindValue( ":dynplaylist", dynamic );
+ cre.bindValue( ":createdOn", now );
if( !m_playlist.isNull() ) {
cre.bindValue( ":guid", m_playlist->guid() );
cre.bindValue( ":shared", m_playlist->shared() );
@@ -111,6 +123,6 @@ DatabaseCommand_CreatePlaylist::createPlaylist( DatabaseImpl* lib, bool dynamic)
cre.bindValue( ":lastmodified", m.value( "lastmodified", 0 ) );
}
qDebug() << "CREATE PLAYLIST:" << cre.boundValues();
-
+
cre.exec();
}
diff --git a/src/libtomahawk/database/databasecommand_loadalldynamicplaylists.cpp b/src/libtomahawk/database/databasecommand_loadalldynamicplaylists.cpp
index 333b596fd..8c5a1bd27 100644
--- a/src/libtomahawk/database/databasecommand_loadalldynamicplaylists.cpp
+++ b/src/libtomahawk/database/databasecommand_loadalldynamicplaylists.cpp
@@ -1,5 +1,5 @@
/* === This file is part of Tomahawk Player - ===
- *
+ *
* Copyright 2010-2011, Christian Muehlhaeuser
*
* Tomahawk is free software: you can redistribute it and/or modify
@@ -29,28 +29,29 @@ using namespace Tomahawk;
void DatabaseCommand_LoadAllDynamicPlaylists::exec( DatabaseImpl* dbi )
{
TomahawkSqlQuery query = dbi->newquery();
-
- query.exec( QString( "SELECT playlist.guid as guid, title, info, creator, lastmodified, shared, currentrevision, dynamic_playlist.pltype, dynamic_playlist.plmode "
+
+ query.exec( QString( "SELECT playlist.guid as guid, title, info, creator, createdOn, lastmodified, shared, currentrevision, dynamic_playlist.pltype, dynamic_playlist.plmode "
"FROM playlist, dynamic_playlist WHERE source %1 AND dynplaylist = 'true' AND playlist.guid = dynamic_playlist.guid" )
.arg( source()->isLocal() ? "IS NULL" :
QString( "=%1" ).arg( source()->id() )
) );
-
+
QList plists;
while ( query.next() )
{
- QVariantList data = QVariantList() << query.value(6).toString() //current rev
+ QVariantList data = QVariantList() << query.value(7).toString() //current rev
<< query.value(1).toString() //title
<< query.value(2).toString() //info
<< query.value(3).toString() //creator
- << query.value(7).toString() // dynamic type
- << static_cast(query.value(8).toInt()) // dynamic mode
- << query.value(5).toBool() //shared
- << query.value(4).toInt() //lastmod
+ << query.value(4).toString() //createdOn
+ << query.value(8).toString() // dynamic type
+ << static_cast(query.value(9).toInt()) // dynamic mode
+ << query.value(6).toBool() //shared
+ << query.value(5).toInt() //lastmod
<< query.value(0).toString(); //GUID
emit playlistLoaded( source(), data );
}
-
+
emit done();
}
diff --git a/src/libtomahawk/database/databasecommand_loadallplaylists.cpp b/src/libtomahawk/database/databasecommand_loadallplaylists.cpp
index db7865767..c2f0782bc 100644
--- a/src/libtomahawk/database/databasecommand_loadallplaylists.cpp
+++ b/src/libtomahawk/database/databasecommand_loadallplaylists.cpp
@@ -1,5 +1,5 @@
/* === This file is part of Tomahawk Player - ===
- *
+ *
* Copyright 2010-2011, Christian Muehlhaeuser
*
* Tomahawk is free software: you can redistribute it and/or modify
@@ -30,7 +30,7 @@ void DatabaseCommand_LoadAllPlaylists::exec( DatabaseImpl* dbi )
{
TomahawkSqlQuery query = dbi->newquery();
- query.exec( QString( "SELECT guid, title, info, creator, lastmodified, shared, currentrevision "
+ query.exec( QString( "SELECT guid, title, info, creator, lastmodified, shared, currentrevision, createdOn "
"FROM playlist WHERE source %1 AND dynplaylist = 'false'" )
.arg( source()->isLocal() ? "IS NULL" :
QString( "= %1" ).arg( source()->id() )
@@ -44,6 +44,7 @@ void DatabaseCommand_LoadAllPlaylists::exec( DatabaseImpl* dbi )
query.value(1).toString(), //title
query.value(2).toString(), //info
query.value(3).toString(), //creator
+ query.value(7).toInt(), //lastmod
query.value(5).toBool(), //shared
query.value(4).toInt(), //lastmod
query.value(0).toString() //GUID
diff --git a/src/libtomahawk/database/databaseimpl.cpp b/src/libtomahawk/database/databaseimpl.cpp
index 85615f00e..e052368f0 100644
--- a/src/libtomahawk/database/databaseimpl.cpp
+++ b/src/libtomahawk/database/databaseimpl.cpp
@@ -1,5 +1,5 @@
/* === This file is part of Tomahawk Player - ===
- *
+ *
* Copyright 2010-2011, Christian Muehlhaeuser
*
* Tomahawk is free software: you can redistribute it and/or modify
@@ -30,6 +30,7 @@
#include "result.h"
#include "artist.h"
#include "album.h"
+#include "utils/tomahawkutils.h"
/* !!!! You need to manually generate schema.sql.h when the schema changes:
cd src/libtomahawk/database
@@ -37,7 +38,7 @@
*/
#include "schema.sql.h"
-#define CURRENT_SCHEMA_VERSION 22
+#define CURRENT_SCHEMA_VERSION 23
DatabaseImpl::DatabaseImpl( const QString& dbname, Database* parent )
@@ -63,21 +64,22 @@ DatabaseImpl::DatabaseImpl( const QString& dbname, Database* parent )
int v = qry.value( 0 ).toInt();
qDebug() << "Current schema is" << v << this->thread();
if ( v != CURRENT_SCHEMA_VERSION )
- {
+ {
QString newname = QString("%1.v%2").arg(dbname).arg(v);
qDebug() << endl << "****************************" << endl;
qDebug() << "Schema version too old: " << v << ". Current version is:" << CURRENT_SCHEMA_VERSION;
qDebug() << "Moving" << dbname << newname;
+ qDebug() << "If the migration fails, you can recover your DB by copying" << newname << "back to" << dbname;
qDebug() << endl << "****************************" << endl;
qry.clear();
qry.finish();
-
+
db.close();
db.removeDatabase( "tomahawk" );
- if( QFile::rename( dbname, newname ) )
+ if( QFile::copy( dbname, newname ) )
{
db = QSqlDatabase::addDatabase( "QSQLITE", "tomahawk" );
db.setDatabaseName( dbname );
@@ -87,6 +89,13 @@ DatabaseImpl::DatabaseImpl( const QString& dbname, Database* parent )
TomahawkSqlQuery query = newquery();
query.exec( "PRAGMA auto_vacuum = FULL" );
schemaUpdated = updateSchema( v );
+
+ if( !schemaUpdated )
+ {
+ Q_ASSERT( false );
+ QTimer::singleShot( 0, qApp, SLOT( quit() ) );
+ }
+
}
else
{
@@ -149,26 +158,73 @@ DatabaseImpl::updateSearchIndex()
bool
-DatabaseImpl::updateSchema( int currentver )
+DatabaseImpl::updateSchema( int oldVersion )
{
- qDebug() << "Create tables... old version is" << currentver;
- QString sql( get_tomahawk_sql() );
- QStringList statements = sql.split( ";", QString::SkipEmptyParts );
- db.transaction();
-
- foreach( const QString& sl, statements )
+ // we are called here with the old database. we must migrate it to the CURRENT_SCHEMA_VERSION from the oldVersion
+ if ( oldVersion == 0 ) // empty database, so create our tables and stuff
{
- QString s( sl.trimmed() );
- if( s.length() == 0 )
- continue;
+ qDebug() << "Create tables... old version is" << oldVersion;
+ QString sql( get_tomahawk_sql() );
+ QStringList statements = sql.split( ";", QString::SkipEmptyParts );
+ db.transaction();
- qDebug() << "Executing:" << s;
- TomahawkSqlQuery query = newquery();
- query.exec( s );
+ foreach( const QString& sl, statements )
+ {
+ QString s( sl.trimmed() );
+ if( s.length() == 0 )
+ continue;
+
+ qDebug() << "Executing:" << s;
+ TomahawkSqlQuery query = newquery();
+ query.exec( s );
+ }
+
+ db.commit();
+ return true;
}
+ else // update in place! run the proper upgrade script
+ {
+ int cur = oldVersion;
+ db.transaction();
+ while ( cur < CURRENT_SCHEMA_VERSION )
+ {
+ cur++;
- db.commit();
- return true;
+ QString path = QString( RESPATH "sql/dbmigrate-%1_to_%2.sql" ).arg( cur - 1 ).arg( cur );
+ QFile script( path );
+ if( !script.exists() || !script.open( QIODevice::ReadOnly ) )
+ {
+ qWarning() << "Failed to find or open upgrade script from" << (cur-1) << "to" << cur << " (" << path << ")! Aborting upgrade..";
+ return false;
+ }
+
+ QString sql = QString::fromUtf8( script.readAll() ).trimmed();
+ QStringList statements = sql.split( ";", QString::SkipEmptyParts );
+ foreach( const QString& sql, statements )
+ {
+ QString clean = cleanSql( sql ).trimmed();
+ if( clean.isEmpty() )
+ continue;
+
+ qDebug() << "Executing upgrade statement:" << clean;
+ TomahawkSqlQuery q = newquery();
+ q.exec( clean );
+ }
+ }
+ db.commit();
+ qDebug() << "DB Upgrade successful!";
+ return true;
+ }
+}
+
+
+QString
+DatabaseImpl::cleanSql( const QString& sql )
+{
+ QString fixed = sql;
+ QRegExp r( "--[^\\n]*" );
+ fixed.replace( r, QString() );
+ return fixed.trimmed();
}
diff --git a/src/libtomahawk/database/databaseimpl.h b/src/libtomahawk/database/databaseimpl.h
index e2965f553..f3551b634 100644
--- a/src/libtomahawk/database/databaseimpl.h
+++ b/src/libtomahawk/database/databaseimpl.h
@@ -1,5 +1,5 @@
/* === This file is part of Tomahawk Player - ===
- *
+ *
* Copyright 2010-2011, Christian Muehlhaeuser
*
* Tomahawk is free software: you can redistribute it and/or modify
@@ -84,9 +84,11 @@ signals:
public slots:
private:
+ QString cleanSql( const QString& sql );
+
bool m_ready;
-
- bool updateSchema( int currentver );
+
+ bool updateSchema( int oldVersion );
QSqlDatabase db;
diff --git a/src/libtomahawk/database/fuzzyindex.cpp b/src/libtomahawk/database/fuzzyindex.cpp
index 25719317c..31d4f5754 100644
--- a/src/libtomahawk/database/fuzzyindex.cpp
+++ b/src/libtomahawk/database/fuzzyindex.cpp
@@ -179,7 +179,7 @@ FuzzyIndex::search( const QString& table, const QString& name )
FuzzyQuery* qry = _CLNEW FuzzyQuery( _CLNEW Term( table.toStdWString().c_str(), DatabaseImpl::sortname( name ).toStdWString().c_str() ) );
hits = m_luceneSearcher->search( qry );
- for ( int i = 0; i < hits->length(); i++ )
+ for ( uint i = 0; i < hits->length(); i++ )
{
Document* d = &hits->doc( i );
diff --git a/src/libtomahawk/database/schema.sql b/src/libtomahawk/database/schema.sql
index e35973508..e2f6ce90d 100644
--- a/src/libtomahawk/database/schema.sql
+++ b/src/libtomahawk/database/schema.sql
@@ -67,13 +67,14 @@ CREATE TABLE IF NOT EXISTS playlist (
creator TEXT,
lastmodified INTEGER NOT NULL DEFAULT 0,
currentrevision TEXT REFERENCES playlist_revision(guid) DEFERRABLE INITIALLY DEFERRED,
- dynplaylist BOOLEAN DEFAULT false
+ dynplaylist BOOLEAN DEFAULT false,
+ createdOn INTEGER NOT NULL DEFAULT 0
);
---INSERT INTO playlist(guid, title, info, currentrevision, dynplaylist)
+--INSERT INTO playlist(guid, title, info, currentrevision, dynplaylist)
--VALUES('dynamic_playlist-guid-1','Test Dynamic Playlist Dynamic','this playlist automatically created and used for testing','revisionguid-1', 1);
---INSERT INTO playlist(guid, title, info, currentrevision, dynplaylist)
+--INSERT INTO playlist(guid, title, info, currentrevision, dynplaylist)
--VALUES('dynamic_playlist-guid-2','Test Dynamic Playlist Static','this playlist automatically created and used for testing','revisionguid-11', 1);
CREATE TABLE IF NOT EXISTS playlist_item (
@@ -129,8 +130,8 @@ CREATE TABLE IF NOT EXISTS dynamic_playlist_controls (
--INSERT INTO dynamic_playlist_controls(id, playlist, selectedType, match, input)
-- VALUES('controlid-2', 'dynamic_playlist-guid-11', "artist", 0, "FooArtist" );
-
-
+
+
CREATE TABLE IF NOT EXISTS dynamic_playlist_revision (
guid TEXT PRIMARY KEY NOT NULL REFERENCES playlist_revision(guid) ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE INITIALLY DEFERRED,
controls TEXT, -- qlist( id, id, id )
@@ -148,7 +149,7 @@ CREATE TABLE IF NOT EXISTS dynamic_playlist_revision (
-- if source=null, file is local to this machine
CREATE TABLE IF NOT EXISTS file (
- id INTEGER PRIMARY KEY AUTOINCREMENT,
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
source INTEGER REFERENCES source(id) ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE INITIALLY DEFERRED,
url TEXT NOT NULL, -- file:///music/foo/bar.mp3,
size INTEGER NOT NULL, -- in bytes
@@ -212,7 +213,7 @@ CREATE TABLE IF NOT EXISTS artist_tags (
);
CREATE INDEX artist_tags_tag ON artist_tags(tag);
--- all other attributes.
+-- all other attributes.
-- like tags that have a value, eg:
-- BPM=120, releaseyear=1980, key=Dminor, composer=Someone
-- NB: since all values are text, numeric values should be zero-padded to a set amount
@@ -263,4 +264,4 @@ CREATE TABLE IF NOT EXISTS settings (
v TEXT NOT NULL DEFAULT ''
);
-INSERT INTO settings(k,v) VALUES('schema_version', '22');
+INSERT INTO settings(k,v) VALUES('schema_version', '23');
diff --git a/src/libtomahawk/database/schema.sql.h b/src/libtomahawk/database/schema.sql.h
index dfd468cf8..864766dc6 100644
--- a/src/libtomahawk/database/schema.sql.h
+++ b/src/libtomahawk/database/schema.sql.h
@@ -1,5 +1,5 @@
/*
- This file was automatically generated from ./schema.sql on Wed Mar 2 01:40:39 CET 2011.
+ This file was automatically generated from schema.sql on Fri Apr 15 15:55:52 EDT 2011.
*/
static const char * tomahawk_schema_sql =
@@ -51,7 +51,8 @@ static const char * tomahawk_schema_sql =
" creator TEXT,"
" lastmodified INTEGER NOT NULL DEFAULT 0,"
" currentrevision TEXT REFERENCES playlist_revision(guid) DEFERRABLE INITIALLY DEFERRED,"
-" dynplaylist BOOLEAN DEFAULT false"
+" dynplaylist BOOLEAN DEFAULT false,"
+" createdOn INTEGER NOT NULL DEFAULT 0"
");"
"CREATE TABLE IF NOT EXISTS playlist_item ("
" guid TEXT PRIMARY KEY,"
@@ -86,8 +87,6 @@ static const char * tomahawk_schema_sql =
" match TEXT,"
" input TEXT"
");"
-""
-""
"CREATE TABLE IF NOT EXISTS dynamic_playlist_revision ("
" guid TEXT PRIMARY KEY NOT NULL REFERENCES playlist_revision(guid) ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE INITIALLY DEFERRED,"
" controls TEXT, "
@@ -173,7 +172,7 @@ static const char * tomahawk_schema_sql =
" k TEXT NOT NULL PRIMARY KEY,"
" v TEXT NOT NULL DEFAULT ''"
");"
-"INSERT INTO settings(k,v) VALUES('schema_version', '22');"
+"INSERT INTO settings(k,v) VALUES('schema_version', '23');"
;
const char * get_tomahawk_sql()
diff --git a/src/libtomahawk/infosystem/infoplugins/lastfmplugin.cpp b/src/libtomahawk/infosystem/infoplugins/lastfmplugin.cpp
index 407031f1e..d34367008 100644
--- a/src/libtomahawk/infosystem/infoplugins/lastfmplugin.cpp
+++ b/src/libtomahawk/infosystem/infoplugins/lastfmplugin.cpp
@@ -134,12 +134,12 @@ LastFmPlugin::getInfo( const QString &caller, const InfoType type, const QVarian
void
LastFmPlugin::nowPlaying( const QString &caller, const InfoType type, const QVariant& data, Tomahawk::InfoSystem::InfoCustomData &customData )
{
- if ( !data.canConvert< Tomahawk::InfoSystem::InfoCustomData >() || !m_scrobbler )
+ if ( !data.canConvert< Tomahawk::InfoSystem::InfoCriteriaHash >() || !m_scrobbler )
{
dataError( caller, type, data, customData );
return;
}
- InfoCustomData hash = data.value< Tomahawk::InfoSystem::InfoCustomData >();
+ InfoCriteriaHash hash = data.value< Tomahawk::InfoSystem::InfoCriteriaHash >();
if ( !hash.contains( "title" ) || !hash.contains( "artist" ) || !hash.contains( "album" ) || !hash.contains( "duration" ) )
{
dataError( caller, type, data, customData );
@@ -149,10 +149,11 @@ LastFmPlugin::nowPlaying( const QString &caller, const InfoType type, const QVar
m_track = lastfm::MutableTrack();
m_track.stamp();
- m_track.setTitle( hash["title"].toString() );
- m_track.setArtist( hash["artist"].toString() );
- m_track.setAlbum( hash["album"].toString() );
- m_track.setDuration( hash["duration"].toUInt() );
+ m_track.setTitle( hash["title"] );
+ m_track.setArtist( hash["artist"] );
+ m_track.setAlbum( hash["album"] );
+ bool ok;
+ m_track.setDuration( hash["duration"].toUInt( &ok ) );
m_track.setSource( lastfm::Track::Player );
m_scrobbler->nowPlaying( m_track );
@@ -183,21 +184,21 @@ void
LastFmPlugin::fetchCoverArt( const QString &caller, const InfoType type, const QVariant& data, Tomahawk::InfoSystem::InfoCustomData &customData )
{
qDebug() << Q_FUNC_INFO;
- if ( !data.canConvert< Tomahawk::InfoSystem::InfoCustomData >() )
+ if ( !data.canConvert< Tomahawk::InfoSystem::InfoCriteriaHash >() )
{
dataError( caller, type, data, customData );
return;
}
- InfoCustomData hash = data.value< Tomahawk::InfoSystem::InfoCustomData >();
+ InfoCriteriaHash hash = data.value< Tomahawk::InfoSystem::InfoCriteriaHash >();
if ( !hash.contains( "artist" ) || !hash.contains( "album" ) )
{
dataError( caller, type, data, customData );
return;
}
- Tomahawk::InfoSystem::InfoCacheCriteria criteria;
- criteria["artist"] = hash["artist"].toString();
- criteria["album"] = hash["album"].toString();
+ Tomahawk::InfoSystem::InfoCriteriaHash criteria;
+ criteria["artist"] = hash["artist"];
+ criteria["album"] = hash["album"];
emit getCachedInfo( criteria, 2419200000, caller, type, data, customData );
}
@@ -207,20 +208,20 @@ void
LastFmPlugin::fetchArtistImages( const QString &caller, const InfoType type, const QVariant& data, Tomahawk::InfoSystem::InfoCustomData &customData )
{
qDebug() << Q_FUNC_INFO;
- if ( !data.canConvert< Tomahawk::InfoSystem::InfoCustomData >() )
+ if ( !data.canConvert< Tomahawk::InfoSystem::InfoCriteriaHash >() )
{
dataError( caller, type, data, customData );
return;
}
- InfoCustomData hash = data.value< Tomahawk::InfoSystem::InfoCustomData >();
+ InfoCriteriaHash hash = data.value< Tomahawk::InfoSystem::InfoCriteriaHash >();
if ( !hash.contains( "artist" ) )
{
dataError( caller, type, data, customData );
return;
}
- Tomahawk::InfoSystem::InfoCacheCriteria criteria;
- criteria["artist"] = hash["artist"].toString();
+ Tomahawk::InfoSystem::InfoCriteriaHash criteria;
+ criteria["artist"] = hash["artist"];
emit getCachedInfo( criteria, 2419200000, caller, type, data, customData );
}
@@ -301,10 +302,10 @@ LastFmPlugin::coverArtReturned()
customData
);
- InfoCustomData origData = reply->property( "origData" ).value< Tomahawk::InfoSystem::InfoCustomData >();
- Tomahawk::InfoSystem::InfoCacheCriteria criteria;
- criteria["artist"] = origData["artist"].toString();
- criteria["album"] = origData["album"].toString();
+ InfoCriteriaHash origData = reply->property( "origData" ).value< Tomahawk::InfoSystem::InfoCriteriaHash >();
+ Tomahawk::InfoSystem::InfoCriteriaHash criteria;
+ criteria["artist"] = origData["artist"];
+ criteria["album"] = origData["album"];
emit updateCache( criteria, 2419200000, type, returnedData );
}
else
@@ -352,9 +353,9 @@ LastFmPlugin::artistImagesReturned()
customData
);
- InfoCustomData origData = reply->property( "origData" ).value< Tomahawk::InfoSystem::InfoCustomData >();
- Tomahawk::InfoSystem::InfoCacheCriteria criteria;
- criteria["artist"] = origData["artist"].toString();
+ InfoCriteriaHash origData = reply->property( "origData" ).value< Tomahawk::InfoSystem::InfoCriteriaHash >();
+ Tomahawk::InfoSystem::InfoCriteriaHash criteria;
+ criteria["artist"] = origData["artist"];
emit updateCache( criteria, 2419200000, type, returnedData );
}
else
diff --git a/src/libtomahawk/infosystem/infoplugins/lastfmplugin.h b/src/libtomahawk/infosystem/infoplugins/lastfmplugin.h
index 1b97b0e0c..55fb6b034 100644
--- a/src/libtomahawk/infosystem/infoplugins/lastfmplugin.h
+++ b/src/libtomahawk/infosystem/infoplugins/lastfmplugin.h
@@ -52,7 +52,7 @@ public slots:
void coverArtReturned();
void artistImagesReturned();
- virtual void notInCacheSlot( Tomahawk::InfoSystem::InfoCacheCriteria criteria, QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, Tomahawk::InfoSystem::InfoCustomData customData );
+ virtual void notInCacheSlot( Tomahawk::InfoSystem::InfoCriteriaHash criteria, QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, Tomahawk::InfoSystem::InfoCustomData customData );
private:
void fetchCoverArt( const QString &caller, const InfoType type, const QVariant& data, Tomahawk::InfoSystem::InfoCustomData &customData );
diff --git a/src/libtomahawk/infosystem/infosystem.cpp b/src/libtomahawk/infosystem/infosystem.cpp
index 6c8357ed6..588ef2940 100644
--- a/src/libtomahawk/infosystem/infosystem.cpp
+++ b/src/libtomahawk/infosystem/infosystem.cpp
@@ -40,21 +40,21 @@ InfoPlugin::InfoPlugin(QObject *parent)
{
QObject::connect(
this,
- SIGNAL( getCachedInfo( Tomahawk::InfoSystem::InfoCacheCriteria, qint64, QString, Tomahawk::InfoSystem::InfoType, QVariant, Tomahawk::InfoSystem::InfoCustomData ) ),
+ SIGNAL( getCachedInfo( Tomahawk::InfoSystem::InfoCriteriaHash, qint64, QString, Tomahawk::InfoSystem::InfoType, QVariant, Tomahawk::InfoSystem::InfoCustomData ) ),
system->getCache(),
- SLOT( getCachedInfoSlot( Tomahawk::InfoSystem::InfoCacheCriteria, qint64, QString, Tomahawk::InfoSystem::InfoType, QVariant, Tomahawk::InfoSystem::InfoCustomData ) )
+ SLOT( getCachedInfoSlot( Tomahawk::InfoSystem::InfoCriteriaHash, qint64, QString, Tomahawk::InfoSystem::InfoType, QVariant, Tomahawk::InfoSystem::InfoCustomData ) )
);
QObject::connect(
system->getCache(),
- SIGNAL( notInCache( Tomahawk::InfoSystem::InfoCacheCriteria, QString, Tomahawk::InfoSystem::InfoType, QVariant, Tomahawk::InfoSystem::InfoCustomData ) ),
+ SIGNAL( notInCache( Tomahawk::InfoSystem::InfoCriteriaHash, QString, Tomahawk::InfoSystem::InfoType, QVariant, Tomahawk::InfoSystem::InfoCustomData ) ),
this,
- SLOT( notInCacheSlot( Tomahawk::InfoSystem::InfoCacheCriteria, QString, Tomahawk::InfoSystem::InfoType, QVariant, Tomahawk::InfoSystem::InfoCustomData ) )
+ SLOT( notInCacheSlot( Tomahawk::InfoSystem::InfoCriteriaHash, QString, Tomahawk::InfoSystem::InfoType, QVariant, Tomahawk::InfoSystem::InfoCustomData ) )
);
QObject::connect(
this,
- SIGNAL( updateCache( Tomahawk::InfoSystem::InfoCacheCriteria, qint64, Tomahawk::InfoSystem::InfoType, QVariant ) ),
+ SIGNAL( updateCache( Tomahawk::InfoSystem::InfoCriteriaHash, qint64, Tomahawk::InfoSystem::InfoType, QVariant ) ),
system->getCache(),
- SLOT( updateCacheSlot( Tomahawk::InfoSystem::InfoCacheCriteria, qint64, Tomahawk::InfoSystem::InfoType, QVariant ) )
+ SLOT( updateCacheSlot( Tomahawk::InfoSystem::InfoCriteriaHash, qint64, Tomahawk::InfoSystem::InfoType, QVariant ) )
);
}
}
@@ -76,7 +76,7 @@ InfoSystem::InfoSystem(QObject *parent)
qDebug() << Q_FUNC_INFO;
qRegisterMetaType< QMap< QString, QMap< QString, QString > > >( "Tomahawk::InfoSystem::InfoGenericMap" );
qRegisterMetaType< QHash< QString, QVariant > >( "Tomahawk::InfoSystem::InfoCustomData" );
- qRegisterMetaType< QHash< QString, QString > >( "Tomahawk::InfoSystem::InfoCacheCriteria" );
+ qRegisterMetaType< QHash< QString, QString > >( "Tomahawk::InfoSystem::InfoCriteriaHash" );
qRegisterMetaType< Tomahawk::InfoSystem::InfoType >( "Tomahawk::InfoSystem::InfoType" );
m_infoSystemCacheThreadController = new QThread( this );
@@ -209,4 +209,4 @@ void InfoSystem::infoSlot(QString target, InfoType type, QVariant input, QVarian
} //namespace InfoSystem
-} //namespace Tomahawk
\ No newline at end of file
+} //namespace Tomahawk
diff --git a/src/libtomahawk/infosystem/infosystem.h b/src/libtomahawk/infosystem/infosystem.h
index 75e674f49..2ccabc1aa 100644
--- a/src/libtomahawk/infosystem/infosystem.h
+++ b/src/libtomahawk/infosystem/infosystem.h
@@ -97,7 +97,7 @@ enum InfoType {
typedef QMap< InfoType, QVariant > InfoMap;
typedef QMap< QString, QMap< QString, QString > > InfoGenericMap;
typedef QHash< QString, QVariant > InfoCustomData;
-typedef QHash< QString, QString > InfoCacheCriteria;
+typedef QHash< QString, QString > InfoCriteriaHash;
class DLLEXPORT InfoPlugin : public QObject
{
@@ -114,14 +114,14 @@ public:
virtual void getInfo( const QString &caller, const InfoType type, const QVariant &data, InfoCustomData customData ) = 0;
signals:
- void getCachedInfo( Tomahawk::InfoSystem::InfoCacheCriteria criteria, qint64 newMaxAge, QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, Tomahawk::InfoSystem::InfoCustomData customData );
- void updateCache( Tomahawk::InfoSystem::InfoCacheCriteria criteria, qint64, Tomahawk::InfoSystem::InfoType type, QVariant output );
+ void getCachedInfo( Tomahawk::InfoSystem::InfoCriteriaHash criteria, qint64 newMaxAge, QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, Tomahawk::InfoSystem::InfoCustomData customData );
+ void updateCache( Tomahawk::InfoSystem::InfoCriteriaHash criteria, qint64, Tomahawk::InfoSystem::InfoType type, QVariant output );
void info( QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, QVariant output, Tomahawk::InfoSystem::InfoCustomData customData );
void finished( QString, Tomahawk::InfoSystem::InfoType );
public slots:
//FIXME: Make pure virtual when everything supports it
- virtual void notInCacheSlot( Tomahawk::InfoSystem::InfoCacheCriteria criteria, QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, Tomahawk::InfoSystem::InfoCustomData customData )
+ virtual void notInCacheSlot( Tomahawk::InfoSystem::InfoCriteriaHash criteria, QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, Tomahawk::InfoSystem::InfoCustomData customData )
{
Q_UNUSED( criteria );
Q_UNUSED( caller );
@@ -180,7 +180,7 @@ private:
}
-inline uint qHash( Tomahawk::InfoSystem::InfoCacheCriteria hash )
+inline uint qHash( Tomahawk::InfoSystem::InfoCriteriaHash hash )
{
QCryptographicHash md5( QCryptographicHash::Md5 );
foreach( QString key, hash.keys() )
@@ -200,6 +200,6 @@ inline uint qHash( Tomahawk::InfoSystem::InfoCacheCriteria hash )
Q_DECLARE_METATYPE( Tomahawk::InfoSystem::InfoGenericMap );
Q_DECLARE_METATYPE( Tomahawk::InfoSystem::InfoCustomData );
-Q_DECLARE_METATYPE( Tomahawk::InfoSystem::InfoCacheCriteria );
+Q_DECLARE_METATYPE( Tomahawk::InfoSystem::InfoCriteriaHash );
#endif // TOMAHAWK_INFOSYSTEM_H
diff --git a/src/libtomahawk/infosystem/infosystemcache.cpp b/src/libtomahawk/infosystem/infosystemcache.cpp
index 9ecdc7435..d35091607 100644
--- a/src/libtomahawk/infosystem/infosystemcache.cpp
+++ b/src/libtomahawk/infosystem/infosystemcache.cpp
@@ -33,6 +33,7 @@ namespace InfoSystem
InfoSystemCache::InfoSystemCache( QObject* parent )
: QObject(parent)
+ , m_cacheRemainingToLoad( 0 )
{
qDebug() << Q_FUNC_INFO;
QString cacheBaseDir = QDesktopServices::storageLocation( QDesktopServices::CacheLocation );
@@ -43,7 +44,10 @@ InfoSystemCache::InfoSystemCache( QObject* parent )
QString cacheFile = cacheDir + '/' + QString::number( i );
QDir dir( cacheDir );
if( dir.exists() && QFile::exists( cacheFile ) )
- loadCache( type, cacheFile );
+ {
+ m_cacheRemainingToLoad++;
+ QMetaObject::invokeMethod( this, "loadCache", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoType, type ), Q_ARG( QString, cacheFile ) );
+ }
}
}
@@ -66,7 +70,7 @@ InfoSystemCache::~InfoSystemCache()
void
-InfoSystemCache::getCachedInfoSlot( Tomahawk::InfoSystem::InfoCacheCriteria criteria, qint64 newMaxAge, QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, Tomahawk::InfoSystem::InfoCustomData customData )
+InfoSystemCache::getCachedInfoSlot( Tomahawk::InfoSystem::InfoCriteriaHash criteria, qint64 newMaxAge, QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, Tomahawk::InfoSystem::InfoCustomData customData )
{
qDebug() << Q_FUNC_INFO;
if ( !m_dataCache.contains( type ) || !m_dataCache[type].contains( criteria ) )
@@ -74,13 +78,20 @@ InfoSystemCache::getCachedInfoSlot( Tomahawk::InfoSystem::InfoCacheCriteria crit
emit notInCache( criteria, caller, type, input, customData );
return;
}
+
+ if ( m_cacheRemainingToLoad > 0 )
+ {
+ qDebug() << "Cache not fully loaded, punting request for a bit";
+ QMetaObject::invokeMethod( this, "getCachedInfoSlot", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoCriteriaHash, criteria ), Q_ARG( qint64, newMaxAge ), Q_ARG( QString, caller ), Q_ARG( Tomahawk::InfoSystem::InfoType, type ), Q_ARG( Tomahawk::InfoSystem::InfoCustomData, customData ) );
+ return;
+ }
- QHash< InfoCacheCriteria, QDateTime > typemaxtimecache = m_maxTimeCache[type];
+ QHash< InfoCriteriaHash, QDateTime > typemaxtimecache = m_maxTimeCache[type];
if ( typemaxtimecache[criteria].toMSecsSinceEpoch() < QDateTime::currentMSecsSinceEpoch() )
{
- QHash< InfoCacheCriteria, QVariant > typedatacache = m_dataCache[type];
- QHash< InfoCacheCriteria, QDateTime > typeinserttimecache = m_insertTimeCache[type];
+ QHash< InfoCriteriaHash, QVariant > typedatacache = m_dataCache[type];
+ QHash< InfoCriteriaHash, QDateTime > typeinserttimecache = m_insertTimeCache[type];
typemaxtimecache.remove( criteria );
m_maxTimeCache[type] = typemaxtimecache;
typedatacache.remove( criteria );
@@ -94,7 +105,7 @@ InfoSystemCache::getCachedInfoSlot( Tomahawk::InfoSystem::InfoCacheCriteria crit
if ( newMaxAge > 0 )
{
- QHash< InfoCacheCriteria, QDateTime > typemaxtimecache = m_maxTimeCache[type];
+ QHash< InfoCriteriaHash, QDateTime > typemaxtimecache = m_maxTimeCache[type];
typemaxtimecache[criteria] = QDateTime::fromMSecsSinceEpoch( QDateTime::currentMSecsSinceEpoch() + newMaxAge );
m_maxTimeCache[type] = typemaxtimecache;
m_dirtySet.insert( type );
@@ -105,12 +116,12 @@ InfoSystemCache::getCachedInfoSlot( Tomahawk::InfoSystem::InfoCacheCriteria crit
void
-InfoSystemCache::updateCacheSlot( Tomahawk::InfoSystem::InfoCacheCriteria criteria, qint64 maxAge, Tomahawk::InfoSystem::InfoType type, QVariant output )
+InfoSystemCache::updateCacheSlot( Tomahawk::InfoSystem::InfoCriteriaHash criteria, qint64 maxAge, Tomahawk::InfoSystem::InfoType type, QVariant output )
{
qDebug() << Q_FUNC_INFO;
- QHash< InfoCacheCriteria, QVariant > typedatacache = m_dataCache[type];
- QHash< InfoCacheCriteria, QDateTime > typeinserttimecache = m_insertTimeCache[type];
- QHash< InfoCacheCriteria, QDateTime > typemaxtimecache = m_maxTimeCache[type];
+ QHash< InfoCriteriaHash, QVariant > typedatacache = m_dataCache[type];
+ QHash< InfoCriteriaHash, QDateTime > typeinserttimecache = m_insertTimeCache[type];
+ QHash< InfoCriteriaHash, QDateTime > typemaxtimecache = m_maxTimeCache[type];
typedatacache[criteria] = output;
typeinserttimecache[criteria] = QDateTime::currentDateTimeUtc();
typemaxtimecache[criteria] = QDateTime::fromMSecsSinceEpoch( QDateTime::currentMSecsSinceEpoch() + maxAge );
@@ -122,7 +133,7 @@ InfoSystemCache::updateCacheSlot( Tomahawk::InfoSystem::InfoCacheCriteria criter
void
-InfoSystemCache::loadCache( InfoType type, const QString &cacheFile )
+InfoSystemCache::loadCache( Tomahawk::InfoSystem::InfoType type, const QString &cacheFile )
{
qDebug() << Q_FUNC_INFO;
QSettings cachedSettings( cacheFile, QSettings::IniFormat );
@@ -132,10 +143,10 @@ InfoSystemCache::loadCache( InfoType type, const QString &cacheFile )
cachedSettings.beginGroup( group );
if ( cachedSettings.value( "maxtime" ).toDateTime().toMSecsSinceEpoch() < QDateTime::currentMSecsSinceEpoch() )
continue;
- QHash< InfoCacheCriteria, QVariant > dataHash = m_dataCache[type];
- QHash< InfoCacheCriteria, QDateTime > insertDateHash = m_insertTimeCache[type];
- QHash< InfoCacheCriteria, QDateTime > maxDateHash = m_maxTimeCache[type];
- InfoCacheCriteria criteria;
+ QHash< InfoCriteriaHash, QVariant > dataHash = m_dataCache[type];
+ QHash< InfoCriteriaHash, QDateTime > insertDateHash = m_insertTimeCache[type];
+ QHash< InfoCriteriaHash, QDateTime > maxDateHash = m_maxTimeCache[type];
+ InfoCriteriaHash criteria;
int numCriteria = cachedSettings.beginReadArray( "criteria" );
for ( int i = 0; i < numCriteria; i++ )
{
@@ -153,11 +164,12 @@ InfoSystemCache::loadCache( InfoType type, const QString &cacheFile )
m_insertTimeCache[type] = insertDateHash;
m_maxTimeCache[type] = maxDateHash;
}
+ m_cacheRemainingToLoad--;
}
void
-InfoSystemCache::saveCache( InfoType type, const QString &cacheDir )
+InfoSystemCache::saveCache( Tomahawk::InfoSystem::InfoType type, const QString &cacheDir )
{
qDebug() << Q_FUNC_INFO;
QDir dir( cacheDir );
@@ -175,7 +187,7 @@ InfoSystemCache::saveCache( InfoType type, const QString &cacheDir )
int criteriaNumber = 0;
- foreach( InfoCacheCriteria criteria, m_dataCache[type].keys() )
+ foreach( InfoCriteriaHash criteria, m_dataCache[type].keys() )
{
cachedSettings.beginGroup( "group_" + QString::number( criteriaNumber ) );
cachedSettings.beginWriteArray( "criteria" );
@@ -201,4 +213,4 @@ InfoSystemCache::saveCache( InfoType type, const QString &cacheDir )
} //namespace InfoSystem
-} //namespace Tomahawk
\ No newline at end of file
+} //namespace Tomahawk
diff --git a/src/libtomahawk/infosystem/infosystemcache.h b/src/libtomahawk/infosystem/infosystemcache.h
index 20307eab8..da0111a84 100644
--- a/src/libtomahawk/infosystem/infosystemcache.h
+++ b/src/libtomahawk/infosystem/infosystemcache.h
@@ -41,25 +41,27 @@ public:
virtual ~InfoSystemCache();
signals:
- void notInCache( Tomahawk::InfoSystem::InfoCacheCriteria criteria, QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, Tomahawk::InfoSystem::InfoCustomData customData );
+ void notInCache( Tomahawk::InfoSystem::InfoCriteriaHash criteria, QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, Tomahawk::InfoSystem::InfoCustomData customData );
void info( QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, QVariant output, Tomahawk::InfoSystem::InfoCustomData customData );
public slots:
- void getCachedInfoSlot( Tomahawk::InfoSystem::InfoCacheCriteria criteria, qint64 newMaxAge, QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, Tomahawk::InfoSystem::InfoCustomData customData );
- void updateCacheSlot( Tomahawk::InfoSystem::InfoCacheCriteria criteria, qint64 maxAge, Tomahawk::InfoSystem::InfoType type, QVariant output );
+ void getCachedInfoSlot( Tomahawk::InfoSystem::InfoCriteriaHash criteria, qint64 newMaxAge, QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input, Tomahawk::InfoSystem::InfoCustomData customData );
+ void updateCacheSlot( Tomahawk::InfoSystem::InfoCriteriaHash criteria, qint64 maxAge, Tomahawk::InfoSystem::InfoType type, QVariant output );
+
+private slots:
+ void loadCache( Tomahawk::InfoSystem::InfoType type, const QString &cacheFile );
+ void saveCache( Tomahawk::InfoSystem::InfoType type, const QString &cacheDir );
private:
- void loadCache( InfoType type, const QString &cacheFile );
- void saveCache( InfoType type, const QString &cacheDir );
-
- QHash< InfoType, QHash< InfoCacheCriteria, QVariant > > m_dataCache;
- QHash< InfoType, QHash< InfoCacheCriteria, QDateTime > > m_insertTimeCache;
- QHash< InfoType, QHash< InfoCacheCriteria, QDateTime > > m_maxTimeCache;
+ QHash< InfoType, QHash< InfoCriteriaHash, QVariant > > m_dataCache;
+ QHash< InfoType, QHash< InfoCriteriaHash, QDateTime > > m_insertTimeCache;
+ QHash< InfoType, QHash< InfoCriteriaHash, QDateTime > > m_maxTimeCache;
QSet< InfoType > m_dirtySet;
+ int m_cacheRemainingToLoad;
};
} //namespace InfoSystem
} //namespace Tomahawk
-#endif //TOMAHAWK_INFOSYSTEMCACHE_H
\ No newline at end of file
+#endif //TOMAHAWK_INFOSYSTEMCACHE_H
diff --git a/src/libtomahawk/network/controlconnection.cpp b/src/libtomahawk/network/controlconnection.cpp
index 24cc6af6d..b1c7a0b50 100644
--- a/src/libtomahawk/network/controlconnection.cpp
+++ b/src/libtomahawk/network/controlconnection.cpp
@@ -118,6 +118,7 @@ ControlConnection::registerSource()
{
qDebug() << Q_FUNC_INFO << m_source->id();
Source* source = (Source*) sender();
+ Q_UNUSED( source )
Q_ASSERT( source == m_source.data() );
// .. but we'll use the shared pointer we've already made:
diff --git a/src/libtomahawk/playlist.cpp b/src/libtomahawk/playlist.cpp
index bf65556da..4281f7265 100644
--- a/src/libtomahawk/playlist.cpp
+++ b/src/libtomahawk/playlist.cpp
@@ -1,5 +1,5 @@
/* === This file is part of Tomahawk Player - ===
- *
+ *
* Copyright 2010-2011, Christian Muehlhaeuser
*
* Tomahawk is free software: you can redistribute it and/or modify
@@ -57,28 +57,28 @@ PlaylistEntry::queryVariant() const
}
-void
+void
PlaylistEntry::setQuery( const Tomahawk::query_ptr& q )
{
m_query = q;
}
-const Tomahawk::query_ptr&
+const Tomahawk::query_ptr&
PlaylistEntry::query() const
{
return m_query;
}
-source_ptr
+source_ptr
PlaylistEntry::lastSource() const
{
return m_lastsource;
}
-void
+void
PlaylistEntry::setLastSource( source_ptr s )
{
m_lastsource = s;
@@ -99,6 +99,7 @@ Playlist::Playlist( const source_ptr& src,
const QString& title,
const QString& info,
const QString& creator,
+ uint createdOn,
bool shared,
int lastmod,
const QString& guid )
@@ -109,6 +110,7 @@ Playlist::Playlist( const source_ptr& src,
, m_title( title )
, m_info( info )
, m_creator( creator )
+ , m_createdOn( createdOn )
, m_lastmodified( lastmod )
, m_shared( shared )
{
@@ -129,6 +131,7 @@ Playlist::Playlist( const source_ptr& author,
, m_title( title )
, m_info ( info )
, m_creator( creator )
+ , m_createdOn( 0 ) // will be set by db command
, m_lastmodified( 0 )
, m_shared( shared )
{
@@ -141,7 +144,7 @@ void
Playlist::init()
{
m_locallyChanged = false;
- connect( Pipeline::instance(), SIGNAL( idle() ), SLOT( onResolvingFinished() ) );
+ connect( Pipeline::instance(), SIGNAL( idle() ), SLOT( onResolvingFinished() ) );
}
@@ -229,7 +232,7 @@ Playlist::reportDeleted( const Tomahawk::playlist_ptr& self )
qDebug() << Q_FUNC_INFO;
Q_ASSERT( self.data() == this );
m_source->collection()->deletePlaylist( self );
-
+
emit deleted( self );
}
@@ -310,24 +313,24 @@ Playlist::setRevision( const QString& rev,
);
return;
}
-
+
PlaylistRevision pr = setNewRevision( rev, neworderedguids, oldorderedguids, is_newest_rev, addedmap );
-
+
if( applied )
m_currentrevision = rev;
pr.applied = applied;
-
+
foreach( const plentry_ptr& entry, m_entries )
{
connect( entry->query().data(), SIGNAL( resultsAdded( QList ) ),
SLOT( onResultsFound( QList ) ), Qt::UniqueConnection );
-
+
}
emit revisionLoaded( pr );
}
-PlaylistRevision
+PlaylistRevision
Playlist::setNewRevision( const QString& rev,
const QList& neworderedguids,
const QList& oldorderedguids,
@@ -340,10 +343,10 @@ Playlist::setNewRevision( const QString& rev,
QMap entriesmap;
foreach( const plentry_ptr& p, m_entries )
entriesmap.insert( p->guid(), p );
-
-
+
+
QList entries;
-
+
foreach( const QString& id, neworderedguids )
{
//qDebug() << "id:" << id;
@@ -351,7 +354,7 @@ Playlist::setNewRevision( const QString& rev,
//qDebug() << "entriesmap:" << entriesmap.count() << entriesmap;
//qDebug() << "addedmap:" << addedmap.count() << addedmap;
//qDebug() << "m_entries" << m_entries;
-
+
if( entriesmap.contains( id ) )
{
entries.append( entriesmap.value( id ) );
@@ -367,13 +370,13 @@ Playlist::setNewRevision( const QString& rev,
Q_ASSERT( false ); // XXX
}
}
-
+
//qDebug() << Q_FUNC_INFO << rev << entries.length() << applied;
-
+
PlaylistRevision pr;
pr.oldrevisionguid = m_currentrevision;
pr.revisionguid = rev;
-
+
// entries that have been removed:
QSet removedguids = oldorderedguids.toSet().subtract( neworderedguids.toSet() );
//qDebug() << "Removedguids:" << removedguids << "oldorederedguids" << oldorderedguids << "newog" << neworderedguids;
@@ -399,10 +402,10 @@ Playlist::setNewRevision( const QString& rev,
}
}
}
-
+
pr.added = addedmap.values();
-
-
+
+
pr.newlist = entries;
return pr;
}
@@ -410,12 +413,12 @@ Playlist::setNewRevision( const QString& rev,
source_ptr
Playlist::author() const
-{
- return m_source;
+{
+ return m_source;
}
-void
+void
Playlist::resolve()
{
QList< query_ptr > qlist;
@@ -462,7 +465,7 @@ void
Playlist::addEntries( const QList& queries, const QString& oldrev )
{
//qDebug() << Q_FUNC_INFO;
-
+
QList el = addEntriesInternal( queries );
QString newrev = uuid();
@@ -470,7 +473,7 @@ Playlist::addEntries( const QList& queries, const QString& oldrev )
}
-QList
+QList
Playlist::addEntriesInternal( const QList& queries )
{
QList el = entries();
@@ -478,16 +481,16 @@ Playlist::addEntriesInternal( const QList& queries )
{
plentry_ptr e( new PlaylistEntry() );
e->setGuid( uuid() );
-
+
if ( query->results().count() )
e->setDuration( query->results().at( 0 )->duration() );
else
e->setDuration( 0 );
-
+
e->setLastmodified( 0 );
e->setAnnotation( "" ); // FIXME
e->setQuery( query );
-
+
el << e;
}
return el;
@@ -500,14 +503,14 @@ Playlist::newEntries( const QList< plentry_ptr >& entries )
QSet currentguids;
foreach( const plentry_ptr& p, m_entries )
currentguids.insert( p->guid() ); // could be cached as member?
-
+
// calc list of newly added entries:
QList added;
foreach( const plentry_ptr& p, entries )
{
if( !currentguids.contains( p->guid() ) )
added << p;
- }
+ }
return added;
}
diff --git a/src/libtomahawk/playlist.h b/src/libtomahawk/playlist.h
index 5147a3d9b..e905517b2 100644
--- a/src/libtomahawk/playlist.h
+++ b/src/libtomahawk/playlist.h
@@ -1,5 +1,5 @@
/* === This file is part of Tomahawk Player - ===
- *
+ *
* Copyright 2010-2011, Christian Muehlhaeuser
*
* Tomahawk is free software: you can redistribute it and/or modify
@@ -77,6 +77,7 @@ public:
source_ptr lastSource() const;
void setLastSource( source_ptr s );
+
private:
QString m_guid;
Tomahawk::query_ptr m_query;
@@ -107,6 +108,7 @@ Q_PROPERTY( QString currentrevision READ currentrevision WRITE setCurrentrevi
Q_PROPERTY( QString title READ title WRITE setTitle )
Q_PROPERTY( QString info READ info WRITE setInfo )
Q_PROPERTY( QString creator READ creator WRITE setCreator )
+Q_PROPERTY( unsigned int createdon READ createdOn WRITE setCreatedOn )
Q_PROPERTY( bool shared READ shared WRITE setShared )
friend class ::DatabaseCommand_LoadAllPlaylists;
@@ -139,6 +141,7 @@ public:
QString guid() const { return m_guid; }
bool shared() const { return m_shared; }
unsigned int lastmodified() const { return m_lastmodified; }
+ uint createdOn() const { return m_createdOn; }
const QList< plentry_ptr >& entries() { return m_entries; }
virtual void addEntry( const Tomahawk::query_ptr& query, const QString& oldrev );
@@ -155,6 +158,7 @@ public:
void setCreator( const QString& s ) { m_creator = s; }
void setGuid( const QString& s ) { m_guid = s; }
void setShared( bool b ) { m_shared = b; }
+ void setCreatedOn( uint createdOn ) { m_createdOn = createdOn; }
//
virtual QList tracks();
@@ -184,7 +188,7 @@ signals:
/// was deleted, eh?
void deleted( const Tomahawk::playlist_ptr& pl );
-
+
void repeatModeChanged( PlaylistInterface::RepeatMode mode );
void shuffleModeChanged( bool enabled );
@@ -214,6 +218,7 @@ protected:
const QString& title,
const QString& info,
const QString& creator,
+ uint createdOn,
bool shared,
int lastmod,
const QString& guid = "" ); // populate db
@@ -247,6 +252,7 @@ private:
QString m_currentrevision;
QString m_guid, m_title, m_info, m_creator;
unsigned int m_lastmodified;
+ unsigned int m_createdOn;
bool m_shared;
QList< plentry_ptr > m_entries;
diff --git a/src/libtomahawk/playlist/artistview.cpp b/src/libtomahawk/playlist/artistview.cpp
index 126f99ecd..722183762 100644
--- a/src/libtomahawk/playlist/artistview.cpp
+++ b/src/libtomahawk/playlist/artistview.cpp
@@ -223,12 +223,12 @@ ArtistView::onScrollTimeout()
{
TreeModelItem* item = m_model->itemFromIndex( m_proxyModel->mapToSource( m_proxyModel->index( i, 0 ) ) );
- Tomahawk::InfoSystem::InfoCustomData trackInfo;
- trackInfo["artist"] = QVariant::fromValue< QString >( item->artist()->name() );
- trackInfo["pptr"] = QVariant::fromValue< qlonglong >( (qlonglong)item );
+ Tomahawk::InfoSystem::InfoCriteriaHash trackInfo;
+ trackInfo["artist"] = item->artist()->name();
+ trackInfo["pptr"] = QString::number( (qlonglong)item );
Tomahawk::InfoSystem::InfoSystem::instance()->getInfo(
s_tmInfoIdentifier, Tomahawk::InfoSystem::InfoArtistImages,
- QVariant::fromValue< Tomahawk::InfoSystem::InfoCustomData >( trackInfo ), Tomahawk::InfoSystem::InfoCustomData() );
+ QVariant::fromValue< Tomahawk::InfoSystem::InfoCriteriaHash >( trackInfo ), Tomahawk::InfoSystem::InfoCustomData() );
}
}
diff --git a/src/libtomahawk/playlist/dynamic/DynamicPlaylist.cpp b/src/libtomahawk/playlist/dynamic/DynamicPlaylist.cpp
index 6186024ee..d81c27324 100644
--- a/src/libtomahawk/playlist/dynamic/DynamicPlaylist.cpp
+++ b/src/libtomahawk/playlist/dynamic/DynamicPlaylist.cpp
@@ -1,5 +1,5 @@
/* === This file is part of Tomahawk Player - ===
- *
+ *
* Copyright 2010-2011, Christian Muehlhaeuser
*
* Tomahawk is free software: you can redistribute it and/or modify
@@ -43,17 +43,18 @@ DynamicPlaylist::~DynamicPlaylist()
}
// Called by loadAllPlaylists command
-DynamicPlaylist::DynamicPlaylist ( const Tomahawk::source_ptr& src,
+DynamicPlaylist::DynamicPlaylist ( const Tomahawk::source_ptr& src,
const QString& currentrevision,
- const QString& title,
- const QString& info,
- const QString& creator,
- const QString& type,
+ const QString& title,
+ const QString& info,
+ const QString& creator,
+ uint createdOn,
+ const QString& type,
GeneratorMode mode,
- bool shared,
- int lastmod,
+ bool shared,
+ int lastmod,
const QString& guid )
- : Playlist( src, currentrevision, title, info, creator, shared, lastmod, guid )
+ : Playlist( src, currentrevision, title, info, creator, createdOn, shared, lastmod, guid )
{
qDebug() << "Creating Dynamic Playlist 1";
// TODO instantiate generator
@@ -63,12 +64,12 @@ DynamicPlaylist::DynamicPlaylist ( const Tomahawk::source_ptr& src,
// called when a new playlist is created (no currentrevision, new guid)
-DynamicPlaylist::DynamicPlaylist ( const Tomahawk::source_ptr& author,
- const QString& guid,
- const QString& title,
- const QString& info,
- const QString& creator,
- const QString& type,
+DynamicPlaylist::DynamicPlaylist ( const Tomahawk::source_ptr& author,
+ const QString& guid,
+ const QString& title,
+ const QString& info,
+ const QString& creator,
+ const QString& type,
bool shared )
: Playlist ( author, guid, title, info, creator, shared )
{
@@ -76,31 +77,31 @@ DynamicPlaylist::DynamicPlaylist ( const Tomahawk::source_ptr& author,
m_generator = geninterface_ptr( GeneratorFactory::create( type ) );
}
-geninterface_ptr
+geninterface_ptr
DynamicPlaylist::generator() const
{
return m_generator;
}
-int
+int
DynamicPlaylist::mode() const
{
return m_generator->mode();
}
-void
+void
DynamicPlaylist::setGenerator(const Tomahawk::geninterface_ptr& gen_ptr)
{
m_generator = gen_ptr;
}
-QString
+QString
DynamicPlaylist::type() const
{
return m_generator->type();
}
-void
+void
DynamicPlaylist::setMode( int mode )
{
m_generator->setMode( (GeneratorMode)mode );
@@ -108,27 +109,27 @@ DynamicPlaylist::setMode( int mode )
-dynplaylist_ptr
-DynamicPlaylist::create( const Tomahawk::source_ptr& author,
- const QString& guid,
- const QString& title,
- const QString& info,
- const QString& creator,
+dynplaylist_ptr
+DynamicPlaylist::create( const Tomahawk::source_ptr& author,
+ const QString& guid,
+ const QString& title,
+ const QString& info,
+ const QString& creator,
bool shared )
{
// default generator
QString type = "";
dynplaylist_ptr dynplaylist = dynplaylist_ptr( new DynamicPlaylist( author, guid, title, info, creator, type, shared ) );
-
+
DatabaseCommand_CreateDynamicPlaylist* cmd = new DatabaseCommand_CreateDynamicPlaylist( author, dynplaylist );
connect( cmd, SIGNAL(finished()), dynplaylist.data(), SIGNAL(created()) );
Database::instance()->enqueue( QSharedPointer(cmd) );
dynplaylist->reportCreated( dynplaylist );
return dynplaylist;
-
+
}
-void
+void
DynamicPlaylist::createNewRevision( const QString& newUuid )
{
if( mode() == Static )
@@ -142,22 +143,22 @@ DynamicPlaylist::createNewRevision( const QString& newUuid )
// create a new revision that will be a static playlist, as it has entries
-void
-DynamicPlaylist::createNewRevision( const QString& newrev,
- const QString& oldrev,
- const QString& type,
- const QList< dyncontrol_ptr>& controls,
+void
+DynamicPlaylist::createNewRevision( const QString& newrev,
+ const QString& oldrev,
+ const QString& type,
+ const QList< dyncontrol_ptr>& controls,
const QList< plentry_ptr >& entries )
{
// get the newly added tracks
QList< plentry_ptr > added = newEntries( entries );
-
+
QStringList orderedguids;
for( int i = 0; i < entries.size(); ++i )
orderedguids << entries.at(i)->guid();
-
+
// no conflict resolution or partial updating for controls. all or nothing baby
-
+
// source making the change (local user in this case)
source_ptr author = SourceList::instance()->getLocal();
// command writes new rev to DB and calls setRevision, which emits our signal
@@ -176,10 +177,10 @@ DynamicPlaylist::createNewRevision( const QString& newrev,
}
// create a new revision that will be an ondemand playlist, as it has no entries
-void
-DynamicPlaylist::createNewRevision( const QString& newrev,
- const QString& oldrev,
- const QString& type,
+void
+DynamicPlaylist::createNewRevision( const QString& newrev,
+ const QString& oldrev,
+ const QString& type,
const QList< dyncontrol_ptr>& controls )
{
// can skip the entry stuff. just overwrite with new info
@@ -196,13 +197,13 @@ DynamicPlaylist::createNewRevision( const QString& newrev,
Database::instance()->enqueue( QSharedPointer( cmd ) );
}
-void
+void
DynamicPlaylist::loadRevision( const QString& rev )
{
qDebug() << Q_FUNC_INFO << "Loading with:" << ( rev.isEmpty() ? currentrevision() : rev );
-
+
DatabaseCommand_LoadDynamicPlaylist* cmd = new DatabaseCommand_LoadDynamicPlaylist( rev.isEmpty() ? currentrevision() : rev );
-
+
if( m_generator->mode() == OnDemand ) {
connect( cmd, SIGNAL( done( QString,
bool,
@@ -230,22 +231,22 @@ DynamicPlaylist::loadRevision( const QString& rev )
QList< QVariantMap >,
bool,
QMap< QString, Tomahawk::plentry_ptr >,
- bool ) ) );
-
+ bool ) ) );
+
}
Database::instance()->enqueue( QSharedPointer( cmd ) );
}
-bool
+bool
DynamicPlaylist::remove( const Tomahawk::dynplaylist_ptr& playlist )
{
DatabaseCommand_DeletePlaylist* cmd = new DatabaseCommand_DeleteDynamicPlaylist( playlist->author(), playlist->guid() );
Database::instance()->enqueue( QSharedPointer(cmd) );
-
+
return false;
}
-void
+void
DynamicPlaylist::reportCreated( const Tomahawk::dynplaylist_ptr& self )
{
qDebug() << Q_FUNC_INFO;
@@ -255,26 +256,26 @@ DynamicPlaylist::reportCreated( const Tomahawk::dynplaylist_ptr& self )
// will emit Collection::playlistCreated(...)
// qDebug() << "Creating dynplaylist belonging to:" << author().data() << author().isNull();
// qDebug() << "REPORTING DYNAMIC PLAYLIST CREATED:" << this << author()->friendlyName();
- author()->collection()->addDynamicPlaylist( self );
+ author()->collection()->addDynamicPlaylist( self );
}
-void
+void
DynamicPlaylist::reportDeleted( const Tomahawk::dynplaylist_ptr& self )
{
qDebug() << Q_FUNC_INFO;
Q_ASSERT( self.data() == this );
// will emit Collection::playlistDeleted(...)
- author()->collection()->deleteDynamicPlaylist( self );
-
+ author()->collection()->deleteDynamicPlaylist( self );
+
emit deleted( self );
}
void DynamicPlaylist::addEntries(const QList< query_ptr >& queries, const QString& oldrev)
{
Q_ASSERT( m_generator->mode() == Static );
-
+
QList el = addEntriesInternal( queries );
-
+
QString newrev = uuid();
createNewRevision( newrev, oldrev, m_generator->type(), m_generator->controls(), el );
}
@@ -283,17 +284,17 @@ void DynamicPlaylist::addEntry(const Tomahawk::query_ptr& query, const QString&
{
QList queries;
queries << query;
-
+
addEntries( queries, oldrev );
}
-void DynamicPlaylist::setRevision( const QString& rev,
- const QList< QString >& neworderedguids,
- const QList< QString >& oldorderedguids,
- const QString& type,
- const QList< dyncontrol_ptr >& controls,
- bool is_newest_rev,
- const QMap< QString, plentry_ptr >& addedmap,
+void DynamicPlaylist::setRevision( const QString& rev,
+ const QList< QString >& neworderedguids,
+ const QList< QString >& oldorderedguids,
+ const QString& type,
+ const QList< dyncontrol_ptr >& controls,
+ bool is_newest_rev,
+ const QMap< QString, plentry_ptr >& addedmap,
bool applied)
{
// we're probably being called by a database worker thread
@@ -315,32 +316,32 @@ void DynamicPlaylist::setRevision( const QString& rev,
if( m_generator->type() != type ) { // new generator needed
m_generator = GeneratorFactory::create( type );
}
-
+
m_generator->setControls( controls );
m_generator->setMode( Static );
-
+
DynamicPlaylistRevision dpr = setNewRevision( rev, neworderedguids, oldorderedguids, is_newest_rev, addedmap );
dpr.applied = applied;
dpr.controls = controls;
dpr.type = type;
dpr.mode = Static;
-
+
if( applied ) {
setCurrentrevision( rev );
}
// qDebug() << "EMITTING REVISION LOADED 1!";
- emit dynamicRevisionLoaded( dpr );
+ emit dynamicRevisionLoaded( dpr );
}
-void
-DynamicPlaylist::setRevision( const QString& rev,
- const QList< QString >& neworderedguids,
- const QList< QString >& oldorderedguids,
- const QString& type,
- const QList< QVariantMap>& controlsV,
- bool is_newest_rev,
- const QMap< QString, Tomahawk::plentry_ptr >& addedmap,
+void
+DynamicPlaylist::setRevision( const QString& rev,
+ const QList< QString >& neworderedguids,
+ const QList< QString >& oldorderedguids,
+ const QString& type,
+ const QList< QVariantMap>& controlsV,
+ bool is_newest_rev,
+ const QMap< QString, Tomahawk::plentry_ptr >& addedmap,
bool applied )
{
if( QThread::currentThread() != thread() )
@@ -358,16 +359,16 @@ DynamicPlaylist::setRevision( const QString& rev,
Q_ARG( bool, applied ) );
return;
}
-
+
QList controls = variantsToControl( controlsV );
setRevision( rev, neworderedguids, oldorderedguids, type, controls, is_newest_rev, addedmap, applied );
-
+
}
-void DynamicPlaylist::setRevision( const QString& rev,
- bool is_newest_rev,
- const QString& type,
- const QList< dyncontrol_ptr >& controls,
+void DynamicPlaylist::setRevision( const QString& rev,
+ bool is_newest_rev,
+ const QString& type,
+ const QList< dyncontrol_ptr >& controls,
bool applied )
{
if( QThread::currentThread() != thread() )
@@ -385,30 +386,30 @@ void DynamicPlaylist::setRevision( const QString& rev,
if( m_generator->type() != type ) { // new generator needed
m_generator = geninterface_ptr( GeneratorFactory::create( type ) );
}
-
+
m_generator->setControls( controls );
m_generator->setMode( OnDemand );
-
+
DynamicPlaylistRevision dpr;
dpr.oldrevisionguid = currentrevision();
dpr.revisionguid = rev;
dpr.controls = controls;
dpr.type = type;
dpr.mode = OnDemand;
-
+
if( applied ) {
setCurrentrevision( rev );
}
// qDebug() << "EMITTING REVISION LOADED 2!";
- emit dynamicRevisionLoaded( dpr );
+ emit dynamicRevisionLoaded( dpr );
}
-void
-DynamicPlaylist::setRevision( const QString& rev,
- bool is_newest_rev,
- const QString& type,
- const QList< QVariantMap >& controlsV,
+void
+DynamicPlaylist::setRevision( const QString& rev,
+ bool is_newest_rev,
+ const QString& type,
+ const QList< QVariantMap >& controlsV,
bool applied )
{
if( QThread::currentThread() != thread() )
@@ -422,8 +423,8 @@ DynamicPlaylist::setRevision( const QString& rev,
QGenericArgument( "QList< QVariantMap >" , (const void*)&controlsV ),
Q_ARG( bool, applied ) );
return;
- }
-
+ }
+
QList controls = variantsToControl( controlsV );
setRevision( rev, is_newest_rev, type, controls, applied );
}
diff --git a/src/libtomahawk/playlist/dynamic/DynamicPlaylist.h b/src/libtomahawk/playlist/dynamic/DynamicPlaylist.h
index 04cd2119e..4312d67b9 100644
--- a/src/libtomahawk/playlist/dynamic/DynamicPlaylist.h
+++ b/src/libtomahawk/playlist/dynamic/DynamicPlaylist.h
@@ -1,5 +1,5 @@
/* === This file is part of Tomahawk Player - ===
- *
+ *
* Copyright 2010-2011, Christian Muehlhaeuser
*
* Tomahawk is free software: you can redistribute it and/or modify
@@ -35,7 +35,7 @@ class DatabaseCommand_CreateDynamicPlaylist;
class DatabaseCollection;
namespace Tomahawk {
-
+
/**
* Subclass of playlist that adds the information needed to store a dynamic playlist.
* It uses normal PlaylistEntries but also has a mode, a generator, and a list of controls
@@ -46,35 +46,35 @@ struct DLLEXPORT DynamicPlaylistRevision : PlaylistRevision
QList< dyncontrol_ptr > controls;
Tomahawk::GeneratorMode mode;
QString type;
-
- DynamicPlaylistRevision( const PlaylistRevision& other )
- {
- revisionguid = other.revisionguid;
- oldrevisionguid = other.oldrevisionguid;
+
+ DynamicPlaylistRevision( const PlaylistRevision& other )
+ {
+ revisionguid = other.revisionguid;
+ oldrevisionguid = other.oldrevisionguid;
newlist = other.newlist;
added = other.added;
removed = other.removed;
- applied = other.applied;
+ applied = other.applied;
}
-
+
DynamicPlaylistRevision() {}
};
class DLLEXPORT DynamicPlaylist : public Playlist
{
Q_OBJECT
-
+
// :-( int becuase qjson chokes on my enums
Q_PROPERTY( int mode WRITE setMode READ mode )
Q_PROPERTY( QString type WRITE setType READ type )
-
+
friend class ::DatabaseCommand_SetDynamicPlaylistRevision;
friend class ::DatabaseCommand_CreateDynamicPlaylist;
friend class ::DatabaseCollection; /// :-(
-
-public:
+
+public:
virtual ~DynamicPlaylist();
-
+
/// Generate an empty dynamic playlist with default generator
static Tomahawk::dynplaylist_ptr create( const source_ptr& author,
const QString& guid,
@@ -84,21 +84,21 @@ public:
bool shared
);
static bool remove( const dynplaylist_ptr& playlist );
-
+
virtual void loadRevision( const QString& rev = "" );
-
+
// :-( int becuase qjson chokes on my enums
int mode() const;
QString type() const;
geninterface_ptr generator() const;
-
+
// Creates a new revision from the playlist in memory. Use this is you change the controls or
// mode of a playlist and want to save it to db/others.
void createNewRevision( const QString& uuid = QString() );
-
+
virtual void addEntries( const QList< query_ptr >& queries, const QString& oldrev );
virtual void addEntry( const Tomahawk::query_ptr& query, const QString& oldrev );
-
+
//
// these need to exist and be public for the json serialization stuff
// you SHOULD NOT call them. They are used for an alternate CTOR method from json.
@@ -108,13 +108,13 @@ public:
void setType( const QString& /*type*/ ) { /** TODO */; }
void setGenerator( const geninterface_ptr& gen_ptr );
//
-
+
signals:
/// emitted when the playlist revision changes (whenever the playlist changes)
void dynamicRevisionLoaded( Tomahawk::DynamicPlaylistRevision );
-
+
void deleted( const Tomahawk::dynplaylist_ptr& pl );
-
+
public slots:
// want to update the playlist from the model?
// generate a newrev using uuid() and call this:
@@ -122,10 +122,10 @@ public slots:
void createNewRevision( const QString& newrev, const QString& oldrev, const QString& type, const QList< dyncontrol_ptr>& controls, const QList< plentry_ptr >& entries );
// if it is ondemand, no entries are needed implicitly sets mode to ondemand
void createNewRevision( const QString& newrev, const QString& oldrev, const QString& type, const QList< dyncontrol_ptr>& controls );
-
+
void reportCreated( const Tomahawk::dynplaylist_ptr& self );
void reportDeleted( const Tomahawk::dynplaylist_ptr& self );
-
+
// called from setdynamicplaylistrevision db cmd
// 4 options, because dbcmds can't create qwidgets:
// static version, qvariant controls
@@ -147,7 +147,7 @@ public slots:
const QList< Tomahawk::dyncontrol_ptr >& controls,
bool is_newest_rev,
const QMap< QString, Tomahawk::plentry_ptr >& addedmap,
- bool applied );
+ bool applied );
// ondemand version
void setRevision( const QString& rev,
bool is_newest_rev,
@@ -166,12 +166,13 @@ private:
const QString& title,
const QString& info,
const QString& creator,
+ uint createdOn,
const QString& type,
GeneratorMode mode,
bool shared,
int lastmod,
const QString& guid = "" ); // populate db
-
+
// called when creating new playlist
explicit DynamicPlaylist( const source_ptr& author,
const QString& guid,
@@ -180,11 +181,11 @@ private:
const QString& creator,
const QString& type,
bool shared );
-
+
private:
QList< dyncontrol_ptr > variantsToControl( const QList< QVariantMap >& controlsV );
geninterface_ptr m_generator;
-
+
};
}; // namespace
diff --git a/src/libtomahawk/playlist/treemodel.cpp b/src/libtomahawk/playlist/treemodel.cpp
index 7d7974974..8830e0bfe 100644
--- a/src/libtomahawk/playlist/treemodel.cpp
+++ b/src/libtomahawk/playlist/treemodel.cpp
@@ -476,14 +476,14 @@ TreeModel::onAlbumsAdded( const QList& albums, const QVaria
albumitem->index = createIndex( parentItem->children.count() - 1, 0, albumitem );
connect( albumitem, SIGNAL( dataChanged() ), SLOT( onDataChanged() ) );
- Tomahawk::InfoSystem::InfoCustomData trackInfo;
- trackInfo["artist"] = QVariant::fromValue< QString >( album->artist()->name() );
- trackInfo["album"] = QVariant::fromValue< QString >( album->name() );
- trackInfo["pptr"] = QVariant::fromValue< qlonglong >( (qlonglong)albumitem );
+ Tomahawk::InfoSystem::InfoCriteriaHash trackInfo;
+ trackInfo["artist"] = album->artist()->name();
+ trackInfo["album"] = album->name();
+ trackInfo["pptr"] = QString::number( (qlonglong)albumitem );
Tomahawk::InfoSystem::InfoSystem::instance()->getInfo(
s_tmInfoIdentifier, Tomahawk::InfoSystem::InfoAlbumCoverArt,
- QVariant::fromValue< Tomahawk::InfoSystem::InfoCustomData >( trackInfo ), Tomahawk::InfoSystem::InfoCustomData() );
+ QVariant::fromValue< Tomahawk::InfoSystem::InfoCriteriaHash >( trackInfo ), Tomahawk::InfoSystem::InfoCustomData() );
}
if ( crows.second > 0 )
@@ -555,7 +555,7 @@ TreeModel::infoSystemInfo( QString caller, Tomahawk::InfoSystem::InfoType type,
return;
}
- Tomahawk::InfoSystem::InfoCustomData pptr = input.value< Tomahawk::InfoSystem::InfoCustomData >();
+ Tomahawk::InfoSystem::InfoCriteriaHash pptr = input.value< Tomahawk::InfoSystem::InfoCriteriaHash >();
Tomahawk::InfoSystem::InfoCustomData returnedData = output.value< Tomahawk::InfoSystem::InfoCustomData >();
const QByteArray ba = returnedData["imgbytes"].toByteArray();
if ( ba.length() )
@@ -563,7 +563,8 @@ TreeModel::infoSystemInfo( QString caller, Tomahawk::InfoSystem::InfoType type,
QPixmap pm;
pm.loadFromData( ba );
- qlonglong p = pptr["pptr"].toLongLong();
+ bool ok;
+ qlonglong p = pptr["pptr"].toLongLong( &ok );
TreeModelItem* ai = reinterpret_cast(p);
if ( pm.isNull() )
diff --git a/src/libtomahawk/playlist/treemodelitem.cpp b/src/libtomahawk/playlist/treemodelitem.cpp
index 9e1c03fa2..09688a56d 100644
--- a/src/libtomahawk/playlist/treemodelitem.cpp
+++ b/src/libtomahawk/playlist/treemodelitem.cpp
@@ -19,6 +19,7 @@
#include "treemodelitem.h"
#include "utils/tomahawkutils.h"
+#include "album.h"
#include
diff --git a/src/scrobbler.cpp b/src/scrobbler.cpp
index 74ad40ae8..2c5d572b4 100644
--- a/src/scrobbler.cpp
+++ b/src/scrobbler.cpp
@@ -74,15 +74,15 @@ Scrobbler::trackStarted( const Tomahawk::result_ptr& track )
scrobble();
}
- Tomahawk::InfoSystem::InfoCustomData trackInfo;
+ Tomahawk::InfoSystem::InfoCriteriaHash trackInfo;
- trackInfo["title"] = QVariant::fromValue< QString >( track->track() );
- trackInfo["artist"] = QVariant::fromValue< QString >( track->artist()->name() );
- trackInfo["album"] = QVariant::fromValue< QString >( track->album()->name() );
- trackInfo["duration"] = QVariant::fromValue< uint >( track->duration() );
+ trackInfo["title"] = track->track();
+ trackInfo["artist"] = track->artist()->name();
+ trackInfo["album"] = track->album()->name();
+ trackInfo["duration"] = QString::number( track->duration() );
Tomahawk::InfoSystem::InfoSystem::instance()->getInfo(
s_scInfoIdentifier, Tomahawk::InfoSystem::InfoMiscSubmitNowPlaying,
- QVariant::fromValue< Tomahawk::InfoSystem::InfoCustomData >( trackInfo ), Tomahawk::InfoSystem::InfoCustomData() );
+ QVariant::fromValue< Tomahawk::InfoSystem::InfoCriteriaHash >( trackInfo ), Tomahawk::InfoSystem::InfoCustomData() );
m_scrobblePoint = ScrobblePoint( track->duration() / 2 );
}
diff --git a/src/sip/CMakeLists.txt b/src/sip/CMakeLists.txt
index 82aa3ae97..3e547058a 100644
--- a/src/sip/CMakeLists.txt
+++ b/src/sip/CMakeLists.txt
@@ -1,10 +1,11 @@
# only build one of them, if ENABLE_JREEN is true, GLOOX_FOUND is automatically set to "false"
-IF( GLOOX_FOUND )
+IF( GLOOX_FOUND AND NOT LIBJREEN_FOUND )
ADD_SUBDIRECTORY( jabber )
-ENDIF( GLOOX_FOUND )
-IF( ENABLE_JREEN )
+ENDIF( GLOOX_FOUND AND NOT LIBJREEN_FOUND )
+
+IF( LIBJREEN_FOUND )
ADD_SUBDIRECTORY( jreen )
-ENDIF( ENABLE_JREEN)
+ENDIF( LIBJREEN_FOUND )
ADD_SUBDIRECTORY( twitter )
ADD_SUBDIRECTORY( zeroconf )
diff --git a/src/sip/jreen/CMakeLists.txt b/src/sip/jreen/CMakeLists.txt
index b06fac816..7cf3d3dd2 100644
--- a/src/sip/jreen/CMakeLists.txt
+++ b/src/sip/jreen/CMakeLists.txt
@@ -9,11 +9,15 @@ add_definitions( -DSIPDLLEXPORT_PRO )
set( jabberSources
jabber.cpp
jabber_p.cpp
+ tomahawksipmessage.cpp
+ tomahawksipmessagefactory.cpp
)
set( jabberHeaders
jabber.h
jabber_p.h
+ tomahawksipmessage.h
+ tomahawksipmessagefactory.h
)
include_directories( . ${CMAKE_CURRENT_BINARY_DIR} ..
@@ -22,7 +26,7 @@ include_directories( . ${CMAKE_CURRENT_BINARY_DIR} ..
)
qt4_wrap_cpp( jabberMoc ${jabberHeaders} )
-add_library( tomahawk_sipjreen SHARED ${jabberSources} ${jabberMoc} )
+add_library( tomahawk_sipjabber SHARED ${jabberSources} ${jabberMoc} )
IF( WIN32 )
SET( OS_SPECIFIC_LINK_LIBRARIES
@@ -33,7 +37,7 @@ SET( OS_SPECIFIC_LINK_LIBRARIES
)
ENDIF( WIN32 )
-target_link_libraries( tomahawk_sipjreen
+target_link_libraries( tomahawk_sipjabber
${QT_LIBRARIES}
${LIBJREEN_LIBRARY}
${OS_SPECIFIC_LINK_LIBRARIES}
@@ -44,4 +48,4 @@ IF( APPLE )
# SET( CMAKE_SHARED_LINKER_FLAGS ${CMAKE_SHARED_LINKER_FLAGS} "-undefined dynamic_lookup" )
ENDIF( APPLE )
-install( TARGETS tomahawk_sipjreen DESTINATION lib${LIB_SUFFIX} )
+install( TARGETS tomahawk_sipjabber DESTINATION lib${LIB_SUFFIX} )
diff --git a/src/sip/jreen/jabber.cpp b/src/sip/jreen/jabber.cpp
index c97067f59..a4b0f1aab 100644
--- a/src/sip/jreen/jabber.cpp
+++ b/src/sip/jreen/jabber.cpp
@@ -1,5 +1,6 @@
/* === This file is part of Tomahawk Player - ===
- *
+ *
+ * Copyright 2010-2011, Dominik Schmidt
* Copyright 2010-2011, Christian Muehlhaeuser
*
* Tomahawk is free software: you can redistribute it and/or modify
@@ -105,8 +106,10 @@ JabberPlugin::connectPlugin( bool startup )
QObject::connect( p, SIGNAL( peerOffline( QString ) ), SIGNAL( peerOffline( QString ) ) );
QObject::connect( p, SIGNAL( msgReceived( QString, QString ) ), SIGNAL( msgReceived( QString, QString ) ) );
- QObject::connect( p, SIGNAL( connected() ), SIGNAL( onConnected() ) );
- QObject::connect( p, SIGNAL( disconnected() ), SIGNAL( onDisconnected() ) );
+ QObject::connect( p, SIGNAL( connected() ), SLOT( onConnected() ) );
+ QObject::connect( p, SIGNAL( disconnected() ), SLOT( onDisconnected() ) );
+
+ QObject::connect( p, SIGNAL( authError( int, QString ) ), SLOT( onAuthError( int, QString ) ) );
return true;
}
@@ -155,6 +158,33 @@ JabberPlugin::onDisconnected()
emit disconnected();
}
+void
+JabberPlugin::onAuthError( int code, const QString& msg )
+{
+ switch( code )
+ {
+ case Jreen::Client::AuthorizationError:
+ emit error( SipPlugin::AuthError, msg );
+ break;
+
+ case Jreen::Client::HostUnknown:
+ case Jreen::Client::ItemNotFound:
+ case Jreen::Client::RemoteStreamError:
+ case Jreen::Client::RemoteConnectionFailed:
+ case Jreen::Client::InternalServerError:
+ case Jreen::Client::SystemShutdown:
+ case Jreen::Client::Conflict:
+ case Jreen::Client::Unknown:
+ emit error( SipPlugin::ConnectionError, msg );
+ break;
+
+ default:
+ qDebug() << "Not all Client::DisconnectReasons checked";
+ Q_ASSERT(false);
+ break;
+ }
+}
+
void
JabberPlugin::sendMsg(const QString& to, const QString& msg)
{
diff --git a/src/sip/jreen/jabber.h b/src/sip/jreen/jabber.h
index ccbbafc0e..75996381d 100644
--- a/src/sip/jreen/jabber.h
+++ b/src/sip/jreen/jabber.h
@@ -1,5 +1,6 @@
/* === This file is part of Tomahawk Player - ===
- *
+ *
+ * Copyright 2010-2011, Dominik Schmidt
* Copyright 2010-2011, Christian Muehlhaeuser
*
* Tomahawk is free software: you can redistribute it and/or modify
@@ -24,7 +25,7 @@
#include "../sipdllmacro.h"
-#define MYNAME "SIPJABBER"
+#define MYNAME "SIPJREEN"
class SIPDLLEXPORT JabberPlugin : public SipPlugin
{
@@ -56,6 +57,7 @@ private slots:
void showAddFriendDialog();
void onConnected();
void onDisconnected();
+ void onAuthError(int code, const QString &msg);
private:
Jabber_p* p;
diff --git a/src/sip/jreen/jabber_p.cpp b/src/sip/jreen/jabber_p.cpp
index 9e4aa8798..5c849f40c 100644
--- a/src/sip/jreen/jabber_p.cpp
+++ b/src/sip/jreen/jabber_p.cpp
@@ -1,5 +1,6 @@
/* === This file is part of Tomahawk Player - ===
- *
+ *
+ * Copyright 2010-2011, Dominik Schmidt
* Copyright 2010-2011, Christian Muehlhaeuser
*
* Tomahawk is free software: you can redistribute it and/or modify
@@ -17,6 +18,16 @@
*/
#include "jabber_p.h"
+#include "tomahawksipmessage.h"
+#include "tomahawksipmessagefactory.h"
+
+#include "config.h"
+#include "utils/tomahawkutils.h"
+
+#include
+
+#include
+#include
#include
#include
@@ -24,58 +35,53 @@
#include
#include
#include
-#include
+#include
+#include
-#include
-#include
+#define TOMAHAWK_FEATURE QLatin1String( "tomahawk:sip:v1" )
-
-//remove
-#include
-#include
-
-using namespace std;
-
-
-#define TOMAHAWK_CAP_NODE_NAME QLatin1String("http://tomahawk-player.org/")
+#define TOMAHAWK_CAP_NODE_NAME QLatin1String( "http://tomahawk-player.org/" )
Jabber_p::Jabber_p( const QString& jid, const QString& password, const QString& server, const int port )
: QObject()
, m_server()
{
qDebug() << Q_FUNC_INFO;
- //qsrand( QTime( 0, 0, 0 ).secsTo( QTime::currentTime() ) );
qsrand(QDateTime::currentDateTime().toTime_t());
- m_presences[Jreen::Presence::Available] = "available";
- m_presences[Jreen::Presence::Chat] = "chat";
- m_presences[Jreen::Presence::Away] = "away";
- m_presences[Jreen::Presence::DND] = "dnd";
- m_presences[Jreen::Presence::XA] = "xa";
- m_presences[Jreen::Presence::Unavailable] = "unavailable";
- m_presences[Jreen::Presence::Probe] = "probe";
- m_presences[Jreen::Presence::Error] = "error";
- m_presences[Jreen::Presence::Invalid] = "invalid";
-
+ // setup JID object
m_jid = Jreen::JID( jid );
+ // general client setup
m_client = new Jreen::Client( jid, password );
- m_client->setResource( QString( "tomahawk-jreen%1" ).arg( QString::number( qrand() % 10000 ) ) );
+ m_client->registerStanzaExtension(new TomahawkSipMessageFactory);
+ m_client->setResource( QString( "tomahawk%1" ).arg( QString::number( qrand() % 10000 ) ) );
+ // setup disco
+ m_client->disco()->setSoftwareVersion( "Tomahawk Player", TOMAHAWK_VERSION, CMAKE_SYSTEM );
+ m_client->disco()->addIdentity( Jreen::Disco::Identity( "client", "type", "tomahawk", "en" ) );
+ m_client->disco()->addFeature( TOMAHAWK_FEATURE );
+
+ // setup caps node, legacy peer detection - used before 0.1
Jreen::Capabilities::Ptr caps = m_client->presence().findExtension();
- caps->setNode(TOMAHAWK_CAP_NODE_NAME);
+ caps->setNode( TOMAHAWK_CAP_NODE_NAME );
+ // print connection parameters
qDebug() << "Our JID set to:" << m_client->jid().full();
qDebug() << "Our Server set to:" << m_client->server();
qDebug() << "Our Port set to" << m_client->port();
+ // setup slots
connect(m_client->connection(), SIGNAL(error(SocketError)), SLOT(onError(SocketError)));
connect(m_client, SIGNAL(serverFeaturesReceived(QSet)), SLOT(onConnect()));
connect(m_client, SIGNAL(disconnected(Jreen::Client::DisconnectReason)), SLOT(onDisconnect(Jreen::Client::DisconnectReason)));
connect(m_client, SIGNAL(destroyed(QObject*)), this, SLOT(onDestroy()));
connect(m_client, SIGNAL(newMessage(Jreen::Message)), SLOT(onNewMessage(Jreen::Message)));
connect(m_client, SIGNAL(newPresence(Jreen::Presence)), SLOT(onNewPresence(Jreen::Presence)));
+ connect(m_client, SIGNAL(newIQ(Jreen::IQ)), SLOT(onNewIq(Jreen::IQ)));
+
+ // connect
qDebug() << "Connecting to the XMPP server...";
m_client->connectToServer();
}
@@ -105,28 +111,57 @@ Jabber_p::disconnect()
void
Jabber_p::sendMsg( const QString& to, const QString& msg )
{
- qDebug() << Q_FUNC_INFO;
- if ( QThread::currentThread() != thread() )
- {
- qDebug() << Q_FUNC_INFO << "invoking in correct thread, not"
- << QThread::currentThread();
-
- QMetaObject::invokeMethod( this, "sendMsg",
- Qt::QueuedConnection,
- Q_ARG( const QString, to ),
- Q_ARG( const QString, msg )
- );
- return;
- }
+ qDebug() << Q_FUNC_INFO << to << msg;
if ( !m_client ) {
return;
}
- qDebug() << Q_FUNC_INFO << to << msg;
- Jreen::Message m( Jreen::Message::Chat, Jreen::JID(to), msg);
+ if( m_legacy_peers.contains( to ) )
+ {
+ qDebug() << Q_FUNC_INFO << to << "Send legacy message" << msg;
+ Jreen::Message m( Jreen::Message::Chat, Jreen::JID(to), msg);
+ m_client->send( m );
- m_client->send( m ); // assuming this is threadsafe
+ return;
+ }
+
+
+ /*******************************************************
+ * Obsolete this by a SipMessage class
+ */
+ QJson::Parser parser;
+ bool ok;
+ QVariant v = parser.parse( msg.toAscii(), &ok );
+ if ( !ok || v.type() != QVariant::Map )
+ {
+ qDebug() << "Invalid JSON in XMPP msg";
+ return;
+ }
+ QVariantMap m = v.toMap();
+ /*******************************************************/
+
+ TomahawkSipMessage *sipMessage;
+ if(m["visible"].toBool())
+ {
+ sipMessage = new TomahawkSipMessage(m["ip"].toString(),
+ m["port"].toInt(),
+ m["uniqname"].toString(),
+ m["key"].toString(),
+ m["visible"].toBool()
+ );
+ }
+ else
+ {
+ sipMessage = new TomahawkSipMessage();
+ }
+
+
+ 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 );
}
@@ -134,23 +169,13 @@ void
Jabber_p::broadcastMsg( const QString &msg )
{
qDebug() << Q_FUNC_INFO;
- if ( QThread::currentThread() != thread() )
- {
- QMetaObject::invokeMethod( this, "broadcastMsg",
- Qt::QueuedConnection,
- Q_ARG(const QString, msg)
- );
- return;
- }
if ( !m_client )
return;
foreach( const QString& jidstr, m_peers.keys() )
{
- qDebug() << "Broadcasting to" << jidstr <<"...";
- Jreen::Message m(Jreen::Message::Chat, Jreen::JID(jidstr), msg, "");
- m_client->send( m );
+ sendMsg( jidstr, msg );
}
}
@@ -158,16 +183,6 @@ Jabber_p::broadcastMsg( const QString &msg )
void
Jabber_p::addContact( const QString& jid, const QString& msg )
{
- if ( QThread::currentThread() != thread() )
- {
- QMetaObject::invokeMethod( this, "addContact",
- Qt::QueuedConnection,
- Q_ARG(const QString, jid),
- Q_ARG(const QString, msg)
- );
- return;
- }
-
// Add contact to the Tomahawk group on the roster
m_roster->add( jid, jid, QStringList() << "Tomahawk" );
@@ -183,6 +198,7 @@ Jabber_p::onConnect()
// have changed our requested /resource
if ( m_client->jid().resource() != m_jid.resource() )
{
+ // TODO: check if this is still neccessary with jreen
m_jid.setResource( m_client->jid().resource() );
QString jidstr( m_jid.full() );
emit jidChanged( jidstr );
@@ -191,22 +207,27 @@ Jabber_p::onConnect()
emit connected();
qDebug() << "Connected as:" << m_jid.full();
- m_client->setPresence(Jreen::Presence::Available, "Tomahawk-JREEN available", 1);
- m_client->disco()->setSoftwareVersion( "Tomahawk JREEN", "0.0.0.0", "Foobar" );
- m_client->setPingInterval(60000);
+ // set presence to least valid value
+ m_client->setPresence(Jreen::Presence::XA, "Got Tomahawk? http://gettomahawk.com", -127);
+
+ // set ping timeout to 15 secs (TODO: verify if this works)
+ m_client->setPingInterval(15000);
+
+ // load roster
m_roster = new Jreen::SimpleRoster( m_client );
m_roster->load();
+ //FIXME: this implementation is totally broken atm, so it's disabled to avoid harm :P
// join MUC with bare jid as nickname
//TODO: make the room a list of rooms and make that configurable
- QString bare(m_jid.bare());
- m_room = new Jreen::MUCRoom(m_client, Jreen::JID(QString("tomahawk@conference.qutim.org/").append(bare.replace("@", "-"))));
+ QString mucNickname = QString( "tomahawk@conference.qutim.org/" ).append( QString( m_jid.bare() ).replace( "@", "-" ) );
+ m_room = new Jreen::MUCRoom(m_client, Jreen::JID( mucNickname ) );
//m_room->setHistorySeconds(0);
//m_room->join();
// treat muc participiants like contacts
- connect(m_room, SIGNAL(messageReceived(Jreen::Message, bool)), this, SLOT(onNewMessage(Jreen::Message)));
- connect(m_room, SIGNAL(presenceReceived(Jreen::Presence,const Jreen::MUCRoom::Participant*)), this, SLOT(onNewPresence(Jreen::Presence)));
+ connect( m_room, SIGNAL( messageReceived( Jreen::Message, bool ) ), this, SLOT( onNewMessage( Jreen::Message ) ) );
+ connect( m_room, SIGNAL( presenceReceived( Jreen::Presence, const Jreen::MUCRoom::Participant* ) ), this, SLOT( onNewPresence( Jreen::Presence ) ) );
}
@@ -262,6 +283,10 @@ Jabber_p::onDisconnect( Jreen::Client::DisconnectReason reason )
}
qDebug() << "Disconnected from server:" << error;
+ if( reason != Jreen::Client::User )
+ {
+ emit authError( reason, error );
+ }
if(reconnect)
QTimer::singleShot(reconnectInSeconds*1000, m_client, SLOT(connectToServer()));
@@ -278,81 +303,151 @@ Jabber_p::onNewMessage( const Jreen::Message& m )
if ( msg.isEmpty() )
return;
- qDebug() << Q_FUNC_INFO << m.from().full() << ":" << m.body();
+ QJson::Parser parser;
+ bool ok;
+ QVariant v = parser.parse( msg.toAscii(), &ok );
+ if ( !ok || v.type() != QVariant::Map )
+ {
+ QString to = from;
+ QString response = QString( tr("I'm sorry -- I'm just an automatic presence used by Tomahawk Player"
+ " (http://gettomahawk.com). If you are getting this message, the person you"
+ " are trying to reach is probably not signed on, so please try again later!") );
+
+ // this is not a sip message, so we send it directly through the client
+ m_client->send( Jreen::Message ( Jreen::Message::Chat, Jreen::JID(to), response) );
+
+ return;
+ }
+
+ qDebug() << Q_FUNC_INFO << "From:" << m.from().full() << ":" << m.body();
emit msgReceived( from, msg );
}
void Jabber_p::onNewPresence( const Jreen::Presence& presence)
{
-
Jreen::JID jid = presence.from();
QString fulljid( jid.full() );
- qDebug() << Q_FUNC_INFO << "handle presence" << fulljid << presence.subtype();
+ qDebug() << Q_FUNC_INFO << "* New presence: " << fulljid << presence.subtype();
if( jid == m_jid )
return;
if ( presence.error() ) {
- qDebug() << Q_FUNC_INFO << "presence error: no tomahawk";
+ //qDebug() << Q_FUNC_INFO << fulljid << "Running tomahawk: no" << "presence error";
return;
}
- // ignore anyone not running tomahawk:
+ // ignore anyone not Running tomahawk:
Jreen::Capabilities::Ptr caps = presence.findExtension();
- if ( caps && (caps->node() == TOMAHAWK_CAP_NODE_NAME ))
+ if ( caps && ( caps->node() == TOMAHAWK_CAP_NODE_NAME ) )
{
- qDebug() << Q_FUNC_INFO << presence.from().full() << "tomahawk detected by caps";
+ // must be a jreen resource, implementation in gloox was broken
+ qDebug() << Q_FUNC_INFO << fulljid << "Running tomahawk: yes" << "caps " << caps->node();
+ handlePeerStatus( fulljid, presence.subtype() );
}
- // this is a hack actually as long as gloox based libsip_jabber is around
- // remove this as soon as everyone is using jreen
- else if( presence.from().resource().startsWith( QLatin1String("tomahawk") ) )
+ else if( caps )
{
- qDebug() << Q_FUNC_INFO << presence.from().full() << "tomahawk detected by resource";
- }
- else if( caps && caps->node() != TOMAHAWK_CAP_NODE_NAME )
- {
- qDebug() << Q_FUNC_INFO << presence.from().full() << "*no tomahawk* detected by caps!" << caps->node() << presence.from().resource();
- return;
+ qDebug() << Q_FUNC_INFO << fulljid << "Running tomahawk: maybe" << "caps " << caps->node()
+ << "requesting disco..";
+
+ // request disco features
+ QString node = caps->node() + '#' + caps->ver();
+
+ Jreen::IQ iq( Jreen::IQ::Get, jid );
+ iq.addExtension( new Jreen::Disco::Info( node ) );
+
+ m_client->send( iq, this, SLOT( onNewIq( Jreen::IQ, int ) ), RequestDisco );
}
else if( !caps )
{
- qDebug() << Q_FUNC_INFO << "no tomahawk detected by resource and !caps";
- return;
+ qDebug() << Q_FUNC_INFO << "Running tomahawk: no" << "no caps";
}
+}
- qDebug() << Q_FUNC_INFO << fulljid << " is a tomahawk resource.";
-
- // "going offline" event
- if ( !presenceMeansOnline( presence.subtype() ) &&
- ( !m_peers.contains( fulljid ) ||
- presenceMeansOnline( m_peers.value( fulljid ) )
- )
- )
+void
+Jabber_p::onNewIq( const Jreen::IQ &iq, int context )
+{
+ if( context == RequestDisco )
{
- m_peers[ fulljid ] = presence.subtype();
- qDebug() << Q_FUNC_INFO << "* Peer goes offline:" << fulljid;
- emit peerOffline( fulljid );
- return;
- }
+ qDebug() << Q_FUNC_INFO << "Received disco IQ...";
+ Jreen::Disco::Info *discoInfo = iq.findExtension().data();
+ if(!discoInfo)
+ return;
+ iq.accept();
- // "coming online" event
- if( presenceMeansOnline( presence.subtype() ) &&
- ( !m_peers.contains( fulljid ) ||
- !presenceMeansOnline( m_peers.value( fulljid ) )
- )
- )
+ QString fulljid = iq.from().full();
+ Jreen::DataForm::Ptr form = discoInfo->form();
+
+ if(discoInfo->features().contains( TOMAHAWK_FEATURE ))
+ {
+ qDebug() << Q_FUNC_INFO << fulljid << "Running tomahawk/feature enabled: yes";
+
+ // the actual presence doesn't matter, it just needs to be "online"
+ handlePeerStatus( fulljid, Jreen::Presence::Available );
+ }
+ else
+ {
+ qDebug() << Q_FUNC_INFO << fulljid << "Running tomahawk/feature enabled: no";
+
+ //LEGACY: accept resources starting with tomahawk too
+ if( iq.from().resource().startsWith("tomahawk") )
+ {
+ qDebug() << Q_FUNC_INFO << fulljid << "Detected legacy tomahawk..";
+
+ // add to legacy peers, so we can send text messages instead of iqs
+ m_legacy_peers.append( fulljid );
+
+ handlePeerStatus( fulljid, Jreen::Presence::Available );
+ }
+ }
+ }
+ else if(context == RequestedDisco)
{
- m_peers[ fulljid ] = presence.subtype();
- qDebug() << Q_FUNC_INFO << "* Peer goes online:" << fulljid;
- emit peerOnline( fulljid );
- return;
+ qDebug() << "Sent IQ(Set), what should be happening here?";
}
+ else if(context == SipMessageSent )
+ {
+ qDebug() << "Sent SipMessage... what now?!";
+ }
+ else
+ {
+ TomahawkSipMessage *sipMessage = iq.findExtension().data();
+ if(sipMessage)
+ {
+ qDebug() << Q_FUNC_INFO << "Got SipMessage ...";
+ qDebug() << "ip" << sipMessage->ip();
+ qDebug() << "port" << sipMessage->port();
+ qDebug() << "uniqname" << sipMessage->uniqname();
+ qDebug() << "key" << sipMessage->key();
+ qDebug() << "visible" << sipMessage->visible();
- //qDebug() << "Updating presence data for" << fulljid;
- m_peers[ fulljid ] = presence.subtype();
+ QVariantMap m;
+ if( sipMessage->visible() )
+ {
+ m["visible"] = true;
+ m["ip"] = sipMessage->ip();
+ m["port"] = sipMessage->port();
+ m["key"] = sipMessage->key();
+ m["uniqname"] = sipMessage->uniqname();
+ }
+ else
+ {
+ m["visible"] = false;
+ }
+
+
+ QJson::Serializer ser;
+ QByteArray ba = ser.serialize( m );
+ QString msg = QString::fromAscii( ba );
+
+ QString from = iq.from().full();
+ qDebug() << Q_FUNC_INFO << "From:" << from << ":" << msg;
+ emit msgReceived( from, msg );
+ }
+ }
}
bool
@@ -369,3 +464,44 @@ Jabber_p::presenceMeansOnline( Jreen::Presence::Type p )
return true;
}
}
+
+void
+Jabber_p::handlePeerStatus( const QString& fulljid, Jreen::Presence::Type presenceType )
+{
+ // "going offline" event
+ if ( !presenceMeansOnline( presenceType ) &&
+ ( !m_peers.contains( fulljid ) ||
+ presenceMeansOnline( m_peers.value( fulljid ) )
+ )
+ )
+ {
+ m_peers[ fulljid ] = presenceType;
+ qDebug() << Q_FUNC_INFO << "* Peer goes offline:" << fulljid;
+
+ // remove peer from legacy peers
+ if( m_legacy_peers.contains( fulljid ) )
+ {
+ m_legacy_peers.removeAll( fulljid );
+ }
+
+ emit peerOffline( fulljid );
+ return;
+ }
+
+ // "coming online" event
+ if( presenceMeansOnline( presenceType ) &&
+ ( !m_peers.contains( fulljid ) ||
+ !presenceMeansOnline( m_peers.value( fulljid ) )
+ )
+ )
+ {
+ m_peers[ fulljid ] = presenceType;
+ qDebug() << Q_FUNC_INFO << "* Peer goes online:" << fulljid;
+ emit peerOnline( fulljid );
+ return;
+ }
+
+ //qDebug() << "Updating presence data for" << fulljid;
+ m_peers[ fulljid ] = presenceType;
+}
+
diff --git a/src/sip/jreen/jabber_p.h b/src/sip/jreen/jabber_p.h
index ab0826f20..ae00f1329 100644
--- a/src/sip/jreen/jabber_p.h
+++ b/src/sip/jreen/jabber_p.h
@@ -1,5 +1,6 @@
/* === This file is part of Tomahawk Player - ===
- *
+ *
+ * Copyright 2010-2011, Dominik Schmidt
* Copyright 2010-2011, Christian Muehlhaeuser
*
* Tomahawk is free software: you can redistribute it and/or modify
@@ -16,20 +17,10 @@
* along with Tomahawk. If not, see .
*/
-/*
- This is the Jabber client that the rest of the app sees
- Gloox stuff should NOT leak outside this class.
- We may replace jreen later, this interface should remain the same.
-*/
#ifndef JABBER_P_H
#define JABBER_P_H
-#include
-#include
-#include
-#include
-
-#include
+#include "../sipdllmacro.h"
#include
#include
@@ -41,16 +32,19 @@
#include
#include
#include
+#include
+#include
+
+#include
+#include
+#include
+#include
#if defined( WIN32 ) || defined( _WIN32 )
-# include
+#include
#endif
-#include "../sipdllmacro.h"
-#include
-#include
-
class SIPDLLEXPORT Jabber_p :
public QObject
{
@@ -87,9 +81,12 @@ private slots:
{
qDebug() << e;
}
+ virtual void onNewIq( const Jreen::IQ &iq, int context = NoContext );
private:
bool presenceMeansOnline( Jreen::Presence::Type p );
+ void handlePeerStatus( const QString &fulljid, Jreen::Presence::Type presenceType );
+
Jreen::Client *m_client;
Jreen::MUCRoom *m_room;
Jreen::SimpleRoster *m_roster;
@@ -97,6 +94,10 @@ private:
QMap m_presences;
QMap m_peers;
QString m_server;
+
+ enum IqContext { NoContext, RequestDisco, RequestedDisco, SipMessageSent };
+
+ QStringList m_legacy_peers;
};
#endif // JABBER_H
diff --git a/src/sip/jreen/tomahawksipmessage.cpp b/src/sip/jreen/tomahawksipmessage.cpp
new file mode 100644
index 000000000..0dce37b0b
--- /dev/null
+++ b/src/sip/jreen/tomahawksipmessage.cpp
@@ -0,0 +1,74 @@
+/****************************************************************************
+ *
+ * This file is part of qutIM
+ *
+ * Copyright (c) 2011 by Nigmatullin Ruslan
+ *
+ ***************************************************************************
+ * *
+ * This file is part of 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 2 of the *
+ * License, or (at your option) any later version. *
+ * *
+ ***************************************************************************
+ ****************************************************************************/
+
+#include "tomahawksipmessage.h"
+
+class TomahawkSipMessagePrivate
+{
+public:
+ QString ip;
+ int port;
+ QString uniqname;
+ QString key;
+ bool visible;
+};
+
+TomahawkSipMessage::TomahawkSipMessage(QString ip, unsigned int port, QString uniqname, QString key, bool visible) : d_ptr(new TomahawkSipMessagePrivate)
+{
+ Q_D(TomahawkSipMessage);
+ d->ip = ip;
+ d->port = port;
+ d->uniqname = uniqname;
+ d->key = key;
+ d->visible = visible;
+}
+
+TomahawkSipMessage::TomahawkSipMessage() : d_ptr(new TomahawkSipMessagePrivate)
+{
+ Q_D(TomahawkSipMessage);
+ d->visible = false;
+ d->port = -1;
+}
+
+
+TomahawkSipMessage::~TomahawkSipMessage()
+{
+}
+
+const QString TomahawkSipMessage::ip() const
+{
+ return d_func()->ip;
+}
+
+unsigned int TomahawkSipMessage::port() const
+{
+ return d_func()->port;
+}
+
+QString TomahawkSipMessage::uniqname() const
+{
+ return d_func()->uniqname;
+}
+
+QString TomahawkSipMessage::key() const
+{
+ return d_func()->key;
+}
+
+bool TomahawkSipMessage::visible() const
+{
+ return d_func()->visible;
+}
diff --git a/src/sip/jreen/tomahawksipmessage.h b/src/sip/jreen/tomahawksipmessage.h
new file mode 100644
index 000000000..da1c376c5
--- /dev/null
+++ b/src/sip/jreen/tomahawksipmessage.h
@@ -0,0 +1,28 @@
+#ifndef ENTITYTIME_H
+#define ENTITYTIME_H
+
+#include
+
+#define TOMAHAWK_SIP_MESSAGE_NS QLatin1String("http://www.tomhawk-player.org/sip/transports")
+
+class TomahawkSipMessagePrivate;
+class TomahawkSipMessage : public Jreen::StanzaExtension
+{
+ J_EXTENSION(TomahawkSipMessage, "")
+ Q_DECLARE_PRIVATE(TomahawkSipMessage)
+ public:
+ TomahawkSipMessage(QString ip, unsigned int port, QString uniqname, QString key, bool visible);
+ // sets visible to false as we dont have any extra information
+ TomahawkSipMessage();
+ ~TomahawkSipMessage();
+
+ const QString ip() const;
+ unsigned int port() const;
+ QString uniqname() const;
+ QString key() const;
+ bool visible() const;
+ private:
+ QScopedPointer d_ptr;
+};
+
+#endif // ENTITYTIME_H
diff --git a/src/sip/jreen/tomahawksipmessagefactory.cpp b/src/sip/jreen/tomahawksipmessagefactory.cpp
new file mode 100644
index 000000000..20a0a9ba8
--- /dev/null
+++ b/src/sip/jreen/tomahawksipmessagefactory.cpp
@@ -0,0 +1,124 @@
+#include "tomahawksipmessagefactory.h"
+//#include "util.h"
+#include
+#include
+#include
+#include
+
+using namespace Jreen;
+
+TomahawkSipMessageFactory::TomahawkSipMessageFactory()
+{
+ m_depth = 0;
+ m_state = AtNowhere;
+}
+
+TomahawkSipMessageFactory::~TomahawkSipMessageFactory()
+{
+}
+
+QStringList TomahawkSipMessageFactory::features() const
+{
+ return QStringList(TOMAHAWK_SIP_MESSAGE_NS);
+}
+
+bool TomahawkSipMessageFactory::canParse(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes)
+{
+ Q_UNUSED(uri);
+ Q_UNUSED(attributes);
+ return name == QLatin1String("tomahawk") && uri == TOMAHAWK_SIP_MESSAGE_NS;
+}
+
+void TomahawkSipMessageFactory::handleStartElement(const QStringRef &name, const QStringRef &uri,
+ const QXmlStreamAttributes &attributes)
+{
+ m_depth++;
+ if (m_depth == 1) {
+ m_state = AtNowhere;
+ m_ip = QString();
+ m_port = -1;
+ m_uniqname = QString();
+ m_key = QString();
+ m_visible = false;
+ } else if (m_depth == 2) {
+ if (name == QLatin1String("transport"))
+ {
+ qDebug() << "Found Transport";
+ m_state = AtTransport;
+
+ m_uniqname = attributes.value(QLatin1String("uniqname")).toString();
+ m_key = attributes.value(QLatin1String("pwd")).toString();
+ m_visible = true;
+ }
+ } else if(m_depth == 3) {
+ if (name == QLatin1String("candidate"))
+ {
+ m_state = AtCandidate;
+ qDebug() << "Found candidate";
+ m_ip = attributes.value(QLatin1String("ip")).toString();
+ m_port = attributes.value(QLatin1String("port")).toString().toInt();
+
+ }
+ }
+ Q_UNUSED(uri);
+ Q_UNUSED(attributes);
+}
+
+void TomahawkSipMessageFactory::handleEndElement(const QStringRef &name, const QStringRef &uri)
+{
+ if (m_depth == 3)
+ m_state = AtNowhere;
+ Q_UNUSED(name);
+ Q_UNUSED(uri);
+ m_depth--;
+}
+
+void TomahawkSipMessageFactory::handleCharacterData(const QStringRef &text)
+{
+ /*if (m_state == AtUtc) {
+ //m_utc = Util::fromStamp(text.toString());
+ } else if (m_state == AtTzo) {
+ QString str = text.toString();
+ int multiple = str.startsWith('-') ? -1 : 1;
+ //QTime delta = QTime::fromString(str.mid(1), QLatin1String("hh:mm"));
+ //m_tzo = multiple * (delta.hour() * 60 + delta.minute());
+ }*/
+ Q_UNUSED(text);
+}
+
+void TomahawkSipMessageFactory::serialize(StanzaExtension *extension, QXmlStreamWriter *writer)
+{
+ TomahawkSipMessage *sipMessage = se_cast(extension);
+
+ writer->writeStartElement(QLatin1String("tomahawk"));
+ writer->writeDefaultNamespace(TOMAHAWK_SIP_MESSAGE_NS);
+
+ if(sipMessage->visible())
+ {
+ // add transport tag
+ writer->writeStartElement(QLatin1String("transport"));
+ writer->writeAttribute(QLatin1String("pwd"), sipMessage->key());
+ writer->writeAttribute(QLatin1String("uniqname"), sipMessage->uniqname());
+
+ writer->writeEmptyElement(QLatin1String("candidate"));
+ writer->writeAttribute(QLatin1String("component"), "1");
+ writer->writeAttribute(QLatin1String("id"), "el0747fg11"); // FIXME
+ writer->writeAttribute(QLatin1String("ip"), sipMessage->ip());
+ writer->writeAttribute(QLatin1String("network"), "1");
+ writer->writeAttribute(QLatin1String("port"), QVariant(sipMessage->port()).toString());
+ writer->writeAttribute(QLatin1String("priority"), "1"); //TODO
+ writer->writeAttribute(QLatin1String("protocol"), "tcp");
+ writer->writeAttribute(QLatin1String("type"), "host"); //FIXME: correct?!
+ writer->writeEndElement();
+ }
+ else
+ {
+ writer->writeEmptyElement(QLatin1String("transport"));
+ }
+ writer->writeEndElement();
+}
+
+StanzaExtension::Ptr TomahawkSipMessageFactory::createExtension()
+{
+ return StanzaExtension::Ptr(new TomahawkSipMessage(m_ip, m_port, m_uniqname, m_key, m_visible));
+}
diff --git a/src/sip/jreen/tomahawksipmessagefactory.h b/src/sip/jreen/tomahawksipmessagefactory.h
new file mode 100644
index 000000000..318208710
--- /dev/null
+++ b/src/sip/jreen/tomahawksipmessagefactory.h
@@ -0,0 +1,46 @@
+/****************************************************************************
+ *
+ * This file is part of qutIM
+ *
+ * Copyright (c) 2011 by Nigmatullin Ruslan
+ *
+ ***************************************************************************
+ * *
+ * This file is part of 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 2 of the *
+ * License, or (at your option) any later version. *
+ * *
+ ***************************************************************************
+ ****************************************************************************/
+
+#ifndef ENTITYTIMEFACTORY_P_H
+#define ENTITYTIMEFACTORY_P_H
+
+#include "tomahawksipmessage.h"
+
+#include
+
+class TomahawkSipMessageFactory : public Jreen::StanzaExtensionFactory
+{
+public:
+ TomahawkSipMessageFactory();
+ virtual ~TomahawkSipMessageFactory();
+ QStringList features() const;
+ bool canParse(const QStringRef &name, const QStringRef &uri, const QXmlStreamAttributes &attributes);
+ 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();
+private:
+ enum State { AtNowhere, AtTransport, AtCandidate } m_state;
+ int m_depth;
+ QString m_ip;
+ int m_port;
+ QString m_uniqname;
+ QString m_key;
+ bool m_visible;
+};
+
+#endif // ENTITYTIMEFACTORY_P_H
diff --git a/src/sourcetree/sourcesmodel.cpp b/src/sourcetree/sourcesmodel.cpp
index 76f1d233d..a27b457f5 100644
--- a/src/sourcetree/sourcesmodel.cpp
+++ b/src/sourcetree/sourcesmodel.cpp
@@ -1,5 +1,5 @@
/* === This file is part of Tomahawk Player - ===
- *
+ *
* Copyright 2010-2011, Christian Muehlhaeuser
*
* Tomahawk is free software: you can redistribute it and/or modify
@@ -38,6 +38,7 @@ SourcesModel::SourcesModel( SourceTreeView* parent )
, m_parent( parent )
{
setColumnCount( 1 );
+ setSortRole( SortRole );
onSourceAdded( SourceList::instance()->sources() );
connect( SourceList::instance(), SIGNAL( sourceAdded( Tomahawk::source_ptr ) ), SLOT( onSourceAdded( Tomahawk::source_ptr ) ) );
@@ -97,6 +98,32 @@ SourcesModel::data( const QModelIndex& index, int role ) const
if ( role == Qt::SizeHintRole )
{
return QSize( 0, 18 );
+ } else if ( role == SortRole )
+ {
+ if ( indexType( index ) == PlaylistSource )
+ {
+ playlist_ptr playlist = indexToPlaylist( index );
+ if ( !playlist.isNull() )
+ return playlist->createdOn();
+ } else if ( indexType( index ) == DynamicPlaylistSource )
+ {
+ dynplaylist_ptr playlist = indexToDynamicPlaylist( index );
+ if ( !playlist.isNull() )
+ return playlist->createdOn();
+ } else if( indexType( index ) == CollectionSource )
+ {
+ source_ptr source = indexToTreeItem( index )->source();
+ if( source.isNull() )
+ return 0; // Super Collection is first
+ else if( source->isLocal() )
+ return 1; // Then Local collection
+ else // then all the rest
+ return 5;
+ } else
+ {
+ qDebug() << "RETURNING NULL SORT DATA!";
+ return QVariant();
+ }
}
return QStandardItemModel::data( index, role );
@@ -152,7 +179,7 @@ SourcesModel::appendItem( const source_ptr& source )
connect( source.data(), SIGNAL( playbackStarted( Tomahawk::query_ptr ) ), SLOT( onSourceChanged() ) );
connect( source.data(), SIGNAL( stateChanged() ), SLOT( onSourceChanged() ) );
}
-
+
return true; // FIXME
}
@@ -246,7 +273,7 @@ SourcesModel::indexToDynamicPlaylist( const QModelIndex& index )
dynplaylist_ptr res;
if ( !index.isValid() )
return res;
-
+
if ( indexType( index ) == DynamicPlaylistSource )
{
QModelIndex idx = index.model()->index( index.row(), 0, index.parent() );
@@ -255,7 +282,7 @@ SourcesModel::indexToDynamicPlaylist( const QModelIndex& index )
if ( playlist )
return *playlist;
}
-
+
return res;
}
@@ -311,12 +338,12 @@ SourcesModel::dynamicPlaylistToIndex( const Tomahawk::dynplaylist_ptr& playlist
for ( int i = 0; i < rowCount(); i++ )
{
QModelIndex pidx = index( i, 0 );
-
+
for ( int j = 0; j < rowCount( pidx ); j++ )
{
QModelIndex idx = index( j, 0, pidx );
SourcesModel::SourceType type = SourcesModel::indexType( idx );
-
+
if ( type == SourcesModel::DynamicPlaylistSource )
{
playlist_ptr p = SourcesModel::indexToDynamicPlaylist( idx );
@@ -325,7 +352,7 @@ SourcesModel::dynamicPlaylistToIndex( const Tomahawk::dynplaylist_ptr& playlist
}
}
}
-
+
return QModelIndex();
}
@@ -367,11 +394,11 @@ SourcesModel::setData( const QModelIndex& index, const QVariant& value, int role
{
playlist = indexToDynamicPlaylist( index ).staticCast< Playlist >();
}
-
+
if ( !playlist.isNull() )
{
playlist->rename( value.toString() );
- QStandardItemModel::setData( index, value, Qt::DisplayRole );
+ QStandardItemModel::setData( index, value, Qt::DisplayRole );
return true;
}
@@ -383,7 +410,7 @@ void
SourcesModel::onSourceChanged()
{
Source* src = qobject_cast< Source* >( sender() );
-
+
for ( int i = 0; i < rowCount(); i++ )
{
QModelIndex idx = index( i, 0 );
diff --git a/src/sourcetree/sourcesmodel.h b/src/sourcetree/sourcesmodel.h
index a9ad5d74b..79d12382e 100644
--- a/src/sourcetree/sourcesmodel.h
+++ b/src/sourcetree/sourcesmodel.h
@@ -1,5 +1,5 @@
/* === This file is part of Tomahawk Player - ===
- *
+ *
* Copyright 2010-2011, Christian Muehlhaeuser
*
* Tomahawk is free software: you can redistribute it and/or modify
@@ -31,15 +31,19 @@ class SourcesModel : public QStandardItemModel
{
Q_OBJECT
-public:
+public:
enum SourceType {
Invalid = -1,
-
+
CollectionSource = 0,
PlaylistSource = 1,
DynamicPlaylistSource = 2
};
-
+
+ enum ExtraRoles {
+ SortRole = Qt::UserRole + 20,
+ };
+
explicit SourcesModel( SourceTreeView* parent = 0 );
virtual QStringList mimeTypes() const;
@@ -58,7 +62,7 @@ public:
QModelIndex playlistToIndex( const Tomahawk::playlist_ptr& playlist );
QModelIndex dynamicPlaylistToIndex( const Tomahawk::dynplaylist_ptr& playlist );
QModelIndex collectionToIndex( const Tomahawk::collection_ptr& collection );
-
+
signals:
void clicked( const QModelIndex& );
diff --git a/src/sourcetree/sourcesproxymodel.cpp b/src/sourcetree/sourcesproxymodel.cpp
index d93cf098e..a53967c58 100644
--- a/src/sourcetree/sourcesproxymodel.cpp
+++ b/src/sourcetree/sourcesproxymodel.cpp
@@ -1,5 +1,5 @@
/* === This file is part of Tomahawk Player - ===
- *
+ *
* Copyright 2010-2011, Christian Muehlhaeuser
*
* Tomahawk is free software: you can redistribute it and/or modify
@@ -32,6 +32,7 @@ SourcesProxyModel::SourcesProxyModel( SourcesModel* model, QObject* parent )
{
setDynamicSortFilter( true );
+ setSortRole( SourcesModel::SortRole );
setSourceModel( model );
}
@@ -63,7 +64,7 @@ SourcesProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex& sourcePar
{
if ( !m_filtered )
return true;
-
+
SourceTreeItem* sti = m_model->indexToTreeItem( sourceModel()->index( sourceRow, 0, sourceParent ) );
if ( sti )
{
diff --git a/src/sourcetree/sourcesproxymodel.h b/src/sourcetree/sourcesproxymodel.h
index add57b257..52b9b6960 100644
--- a/src/sourcetree/sourcesproxymodel.h
+++ b/src/sourcetree/sourcesproxymodel.h
@@ -1,5 +1,5 @@
/* === This file is part of Tomahawk Player - ===
- *
+ *
* Copyright 2010-2011, Christian Muehlhaeuser
*
* Tomahawk is free software: you can redistribute it and/or modify
diff --git a/src/sourcetree/sourcetreeview.cpp b/src/sourcetree/sourcetreeview.cpp
index 4935b8d0e..6693bd106 100644
--- a/src/sourcetree/sourcetreeview.cpp
+++ b/src/sourcetree/sourcetreeview.cpp
@@ -80,6 +80,9 @@ SourceTreeView::SourceTreeView( QWidget* parent )
setIndentation( 16 );
setAnimated( true );
+ setSortingEnabled( true );
+ sortByColumn( 1, Qt::AscendingOrder );
+
setItemDelegate( new SourceDelegate( this ) );
setContextMenuPolicy( Qt::CustomContextMenu );
diff --git a/src/tomahawkapp.cpp b/src/tomahawkapp.cpp
index ea5311844..77c33ab96 100644
--- a/src/tomahawkapp.cpp
+++ b/src/tomahawkapp.cpp
@@ -154,10 +154,11 @@ TomahawkApp::TomahawkApp( int& argc, char *argv[] )
, m_mainwindow( 0 )
{
qDebug() << "TomahawkApp thread:" << this->thread();
- setOrganizationName( QLatin1String( ORGANIZATION_NAME ) );
- setOrganizationDomain( QLatin1String( ORGANIZATION_DOMAIN ) );
- setApplicationName( QLatin1String( APPLICATION_NAME ) );
- setApplicationVersion( QLatin1String( VERSION ) );
+ setOrganizationName( QLatin1String( TOMAHAWK_ORGANIZATION_NAME ) );
+ setOrganizationDomain( QLatin1String( TOMAHAWK_ORGANIZATION_DOMAIN ) );
+ setApplicationName( QLatin1String( TOMAHAWK_APPLICATION_NAME ) );
+ setApplicationVersion( QLatin1String( TOMAHAWK_VERSION ) );
+ registerMetaTypes();
setupLogfile();
}
diff --git a/src/web/api_v1.cpp b/src/web/api_v1.cpp
index d0a3b0475..800935d4c 100644
--- a/src/web/api_v1.cpp
+++ b/src/web/api_v1.cpp
@@ -1,5 +1,5 @@
/* === This file is part of Tomahawk Player - ===
- *
+ *
* Copyright 2010-2011, Christian Muehlhaeuser
*
* Tomahawk is free software: you can redistribute it and/or modify
@@ -71,7 +71,7 @@ Api_v1::auth_2( QxtWebRequestEvent* event, QString arg )
else
qDebug() << "Failed parsing url parameters: " << part;
}
-
+
qDebug() << "has query items:" << pieces;
if( !params.contains( "website" ) || !params.contains( "name" ) || !params.contains( "formtoken" ) )
{
@@ -165,7 +165,8 @@ Api_v1::sid( QxtWebRequestEvent* event, QString unused )
QxtWebPageEvent* e = new QxtWebPageEvent( event->sessionID, event->requestID, iodev );
e->streaming = iodev->isSequential();
e->contentType = rp->mimetype().toAscii();
- e->headers.insert( "Content-Length", QString::number( rp->size() ) );
+ if( rp->size() > 0 )
+ e->headers.insert( "Content-Length", QString::number( rp->size() ) );
postEvent( e );
}
@@ -341,7 +342,7 @@ Api_v1::sendWebpageWithArgs( QxtWebRequestEvent* event, const QString& filenameS
// workaround for receiverurl
if( !args.keys().contains( "URL" ) )
html.replace( QString( "<%URL%>" ).toLatin1(), QByteArray() );
-
+
QxtWebPageEvent* e = new QxtWebPageEvent( event->sessionID, event->requestID, html );
postEvent( e );
diff --git a/thirdparty/CMakeLists.txt b/thirdparty/CMakeLists.txt
index ca840ac1f..d04c724b3 100644
--- a/thirdparty/CMakeLists.txt
+++ b/thirdparty/CMakeLists.txt
@@ -1,5 +1,5 @@
-add_subdirectory( jdns )
-add_subdirectory( qtweetlib )
+ADD_SUBDIRECTORY( jdns )
+ADD_SUBDIRECTORY( qtweetlib )
ADD_SUBDIRECTORY( libportfwd )
ADD_SUBDIRECTORY( qxt )
ADD_SUBDIRECTORY( liblastfm2 )
diff --git a/thirdparty/jreen b/thirdparty/jreen
index 126ef9d96..ff5d1fdc9 160000
--- a/thirdparty/jreen
+++ b/thirdparty/jreen
@@ -1 +1 @@
-Subproject commit 126ef9d96bf774b9808a16dd8c94001af408528b
+Subproject commit ff5d1fdc9f416a0e10e1e571e51a70ca377e6811
diff --git a/thirdparty/liblastfm2/src/types/Track.cpp b/thirdparty/liblastfm2/src/types/Track.cpp
index cececee1b..64d8288d0 100644
--- a/thirdparty/liblastfm2/src/types/Track.cpp
+++ b/thirdparty/liblastfm2/src/types/Track.cpp
@@ -33,9 +33,9 @@ lastfm::TrackData::TrackData()
rating( 0 ),
fpid( -1 ),
loved( false ),
- null( false ),
scrobbleStatus( Track::Null ),
- scrobbleError( Track::None )
+ scrobbleError( Track::None ),
+ null( false )
{}
lastfm::Track::Track()