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()