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

Compare commits

...

67 Commits

Author SHA1 Message Date
Michael Zanetti
a4d01685cf Merge branch 'master' into decltest 2012-08-03 22:19:56 +02:00
Michael Zanetti
467cb26006 add artist mode for stations 2012-08-03 21:53:56 +02:00
Michael Zanetti
8f20c828fa Merge branch 'master' into decltest
Conflicts:
	resources.qrc
	src/libtomahawk/CMakeLists.txt
	src/libtomahawk/widgets/infowidgets/ArtistInfoWidget.cpp
2012-08-03 20:45:26 +02:00
Michael Zanetti
012bb49328 remove useless assert 2012-08-03 18:46:08 +02:00
Michael Zanetti
8e91ab63ca some more testing work for stations 2012-07-28 14:16:49 +02:00
Michael Zanetti
52d5dbaf4d some more work on the stations 2012-07-25 22:05:39 +02:00
Michael Zanetti
cdfde7ecc3 Merge branch 'decltest' of github.com:tomahawk-player/tomahawk into decltest 2012-07-21 15:37:24 +02:00
Michael Zanetti
d5935b632f some more work on the station config 2012-07-21 15:37:08 +02:00
Christian Muehlhaeuser
e50c661496 Merge branch 'master' into decltest 2012-07-21 15:07:10 +02:00
Christian Muehlhaeuser
ecc6b679a7 Merge branch 'master' into decltest 2012-07-21 14:19:42 +02:00
Christian Muehlhaeuser
ee2670b813 * Mutex protect hash access. 2012-07-21 14:14:45 +02:00
Christian Muehlhaeuser
95b43964df * Use largest album cover size last.fm offers. 2012-07-21 10:48:40 +02:00
Christian Muehlhaeuser
e67653dbfd * Assert when trying to create an empty PlayableItem. 2012-07-21 10:10:43 +02:00
Christian Muehlhaeuser
125fa25d07 * Fixed getting artist covers from DeclarativeCoverArtProvider. 2012-07-21 09:22:14 +02:00
Christian Muehlhaeuser
c77aecd59f * Add an assert for Jason. 2012-07-20 14:42:22 +02:00
Christian Muehlhaeuser
d16ed39dbe * Fixed cover retrieval via DeclarativeCoverArtProvider. 2012-07-20 13:42:14 +02:00
Michael Zanetti
c1df1387f0 dunno why, but QML seems to dislike jumps in enums... remove the Qt::UserRole + 100 2012-07-19 22:40:06 +02:00
Michael Zanetti
6d67b129d2 fix warning 2012-07-19 22:39:59 +02:00
Michael Zanetti
07d91b1d58 fix compilation without -fpermissive 2012-07-19 21:39:15 +02:00
Michael Zanetti
87966d5636 - make the station stuff adapt to high DPIs
- more work on the config dialog
2012-07-19 21:38:15 +02:00
Christian Muehlhaeuser
83f9d86e1d * Work on image provider & unique cover IDs. 2012-07-19 21:35:54 +02:00
Michael Zanetti
b02f8c0d9c make stations behave correctly (preload some tracks and switch to dynamic mode on play) 2012-07-19 18:27:44 +02:00
Michael Zanetti
885c52a042 only fetch more track if they are finished resolving and there are not enough tracks available yet 2012-07-15 13:18:37 +02:00
Michael Zanetti
68114e1f59 Merge branch 'decltest' of github.com:tomahawk-player/tomahawk into decltest 2012-07-14 16:20:12 +02:00
Michael Zanetti
710e570845 restructured QML 2012-07-14 16:19:35 +02:00
Christian Muehlhaeuser
ff44238d06 * Lock mutex when adding to the static hashes in Artist and Album. 2012-07-14 14:02:59 +02:00
Christian Muehlhaeuser
71eb1e916a * Added getByUniqueId( uuid ) methods to Artist, Album and Query. 2012-07-14 13:20:38 +02:00
Christian Muehlhaeuser
0314760451 * Disable infobar for stations. 2012-07-14 12:45:19 +02:00
Christian Muehlhaeuser
b9a909eb56 * Properly store / restore DynamicQmlWidgets. 2012-07-14 12:43:13 +02:00
Michael Zanetti
73f05971e4 add missing files 2012-07-14 11:55:16 +02:00
Michael Zanetti
c0c2cc6234 Merge branch 'decltest' of github.com:tomahawk-player/tomahawk into decltest 2012-07-14 11:54:02 +02:00
Michael Zanetti
ba6b14863c some more work on the station qml 2012-07-14 11:53:19 +02:00
Leo Franchi
309a6843f0 Merge branch 'master' into decltest 2012-07-13 14:25:11 -04:00
Michael Zanetti
a89d20665f more work on the new station view 2012-07-12 16:40:19 +02:00
Michael Zanetti
976a2eeb0a Merge branch 'master' of github.com:tomahawk-player/tomahawk into decltest 2012-07-10 19:39:31 +02:00
Michael Zanetti
6dea6dc0a5 a try to prefill the station with more songs 2012-07-10 07:54:56 +02:00
Michael Zanetti
6dc8e98003 connect also to resultsChanged 2012-07-07 21:27:28 +02:00
Christian Muehlhaeuser
d571a79746 * Don't return unresolved queries when proxy-model is supposed to filter out offline / unplayable tracks. 2012-07-06 06:32:01 +02:00
Christian Muehlhaeuser
457c916101 Merge branch 'master' into decltest 2012-07-06 06:21:02 +02:00
Christian Muehlhaeuser
56e73fb274 * No need to hook up to query's coverChanged() signal anymore. 2012-07-06 03:40:50 +02:00
Christian Muehlhaeuser
56dd8d47db Merge branch 'master' into decltest 2012-07-06 02:16:21 +02:00
Michael Zanetti
3c942b1249 played around with the QML path a bit... 2012-07-05 14:42:49 +02:00
Michael Zanetti
68de791e8c yay! we have album covers! 2012-07-05 13:58:28 +02:00
Christian Muehlhaeuser
41a37b4690 * Fixed clash between model & proxymodel user-roles. 2012-07-05 13:34:59 +02:00
Michael Zanetti
9e6dbcc7b1 fix covers again after using the proxymodel 2012-07-05 13:30:29 +02:00
Michael Zanetti
64f4445a01 use the proxymodel instead of the model directly 2012-07-05 13:17:12 +02:00
Michael Zanetti
0a1f2304e9 Merge branch 'master' of github.com:tomahawk-player/tomahawk into decltest 2012-07-05 12:15:27 +02:00
Michael Zanetti
8f465b2984 removed unneeded slot previously used for debugging 2012-07-05 11:47:34 +02:00
Michael Zanetti
2d32a2db90 added artwork to the stations view 2012-07-05 11:43:19 +02:00
Christian Muehlhaeuser
f5b3c20c4c * Merged master into decltest. 2012-07-04 22:44:33 +02:00
Michael Zanetti
abb8217286 more work on the station qml stuff 2012-07-04 17:54:01 +02:00
Michael Zanetti
b48896157d Merge branch 'decltest' of github.com:tomahawk-player/tomahawk into decltest 2012-07-04 12:08:45 +02:00
Christian Muehlhaeuser
692a4043e8 * Call startOnDemand() when initializing DynamicQmlWidget. Not sure if we need to wait for a revision to be loaded first, though. 2012-07-03 23:43:32 +02:00
Christian Muehlhaeuser
e81baf0eb7 * Added PlayableRoles and mapped them to the according column. 2012-07-03 23:42:56 +02:00
Michael Zanetti
bbdb15c53e a very very basic pathview for covers 2012-07-03 18:06:19 +02:00
Christian Muehlhaeuser
5f61e3b1bd * Merged master into declspec. 2012-07-03 17:54:22 +02:00
Christian Muehlhaeuser
6bc9f88189 * Setup a DynamicQmlWidget when showing a station. 2012-07-03 17:07:08 +02:00
Christian Muehlhaeuser
92d7757e47 * Setup (proxy-)model and load dynamic playlist in DynamicQmlWidget. 2012-07-03 17:07:08 +02:00
Michael Zanetti
2fb8b57e25 added qml file template for stations 2012-07-03 16:51:35 +02:00
Christian Muehlhaeuser
c295514598 * Make DynamicQmlWidget a proper ViewPage. 2012-07-03 16:37:47 +02:00
Michael Zanetti
c05bae9e8c added DynamicQmlWidget (not doing anything yet) 2012-07-03 16:05:34 +02:00
Michael Zanetti
051282be06 moved qml file to rc to avoid path issues 2012-07-02 01:12:32 +02:00
Michael Zanetti
fb0a88aa98 make reflection look nice in pathview and remove it from gridview 2012-07-02 00:58:08 +02:00
Michael Zanetti
fc69e7d08d added an ugly but still impressive (for a proof of concept) mirror effect for cover art 2012-07-02 00:34:59 +02:00
Michael Zanetti
02708629ca and another one just to show it off to muesli 2012-07-02 00:19:45 +02:00
Michael Zanetti
d894116e8e take that, QWidget! 2012-07-01 23:48:46 +02:00
Michael Zanetti
5c47ae96ab testcomit for qtdeclarative 2012-07-01 16:37:46 +02:00
43 changed files with 2097 additions and 87 deletions

View File

@@ -88,7 +88,7 @@ IF( NOT BUILD_GUI )
MESSAGE( STATUS "Building Tomahawk ${TOMAHAWK_VERSION} in HEADLESS mode ***" )
ELSE()
MESSAGE( STATUS "Building Tomahawk ${TOMAHAWK_VERSION} full GUI version ***" )
LIST(APPEND NEEDED_QT4_COMPONENTS "QtGui" "QtWebkit" "QtUiTools" )
LIST(APPEND NEEDED_QT4_COMPONENTS "QtGui" "QtWebkit" "QtUiTools" "QtDeclarative" )
ENDIF()
IF( BUILD_GUI AND UNIX AND NOT APPLE )

147
CMakeLists.txt.user.2.3pre1 Normal file
View File

@@ -0,0 +1,147 @@
<!DOCTYPE QtCreatorProject>
<qtcreator>
<data>
<variable>ProjectExplorer.Project.ActiveTarget</variable>
<value type="int">0</value>
</data>
<data>
<variable>ProjectExplorer.Project.EditorSettings</variable>
<valuemap type="QVariantMap">
<value key="EditorConfiguration.AutoIndent" type="bool">true</value>
<value key="EditorConfiguration.AutoSpacesForTabs" type="bool">false</value>
<value key="EditorConfiguration.Codec" type="QByteArray">UTF-8</value>
<value key="EditorConfiguration.DoubleIndentBlocks" type="bool">false</value>
<value key="EditorConfiguration.IndentBraces" type="bool">false</value>
<value key="EditorConfiguration.IndentSize" type="int">4</value>
<value key="EditorConfiguration.MouseNavigation" type="bool">true</value>
<value key="EditorConfiguration.PaddingMode" type="int">1</value>
<value key="EditorConfiguration.ScrollWheelZooming" type="bool">true</value>
<value key="EditorConfiguration.SmartBackspace" type="bool">false</value>
<value key="EditorConfiguration.SpacesForTabs" type="bool">true</value>
<value key="EditorConfiguration.TabKeyBehavior" type="int">0</value>
<value key="EditorConfiguration.TabSize" type="int">8</value>
<value key="EditorConfiguration.UseGlobal" type="bool">true</value>
<value key="EditorConfiguration.Utf8BomBehavior" type="int">1</value>
<value key="EditorConfiguration.addFinalNewLine" type="bool">true</value>
<value key="EditorConfiguration.cleanIndentation" type="bool">true</value>
<value key="EditorConfiguration.cleanWhitespace" type="bool">true</value>
<value key="EditorConfiguration.inEntireDocument" type="bool">false</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.Target.0</variable>
<valuemap type="QVariantMap">
<value key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName" type="QString">Desktop</value>
<value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString"></value>
<value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">CMakeProjectManager.DefaultCMakeTarget</value>
<value key="ProjectExplorer.Target.ActiveBuildConfiguration" type="int">0</value>
<value key="ProjectExplorer.Target.ActiveDeployConfiguration" type="int">0</value>
<value key="ProjectExplorer.Target.ActiveRunConfiguration" type="int">0</value>
<valuemap key="ProjectExplorer.Target.BuildConfiguration.0" type="QVariantMap">
<value key="CMakeProjectManager.CMakeBuildConfiguration.BuildDirectory" type="QString">/home/micha/Develop/tomahawk-build</value>
<value key="CMakeProjectManager.CMakeBuildConfiguration.ToolChain" type="QString">ProjectExplorer.ToolChain.Gcc:/usr/bin/g++.x86-linux-generic-elf-64bit.</value>
<value key="ProjectExplorer.BuildCOnfiguration.ToolChain" type="QString">ProjectExplorer.ToolChain.Gcc:/usr/bin/g++.x86-linux-generic-elf-64bit.</value>
<valuemap key="ProjectExplorer.BuildConfiguration.BuildStepList.0" type="QVariantMap">
<valuemap key="ProjectExplorer.BuildStepList.Step.0" type="QVariantMap">
<value key="CMakeProjectManager.MakeStep.AdditionalArguments" type="QString"></value>
<valuelist key="CMakeProjectManager.MakeStep.BuildTargets" type="QVariantList"/>
<value key="CMakeProjectManager.MakeStep.Clean" type="bool">false</value>
<value key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName" type="QString">Make</value>
<value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString"></value>
<value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">CMakeProjectManager.MakeStep</value>
</valuemap>
<value key="ProjectExplorer.BuildStepList.StepsCount" type="int">1</value>
<value key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName" type="QString">Build</value>
<value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString"></value>
<value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap key="ProjectExplorer.BuildConfiguration.BuildStepList.1" type="QVariantMap">
<valuemap key="ProjectExplorer.BuildStepList.Step.0" type="QVariantMap">
<value key="CMakeProjectManager.MakeStep.AdditionalArguments" type="QString">clean</value>
<valuelist key="CMakeProjectManager.MakeStep.BuildTargets" type="QVariantList"/>
<value key="CMakeProjectManager.MakeStep.Clean" type="bool">true</value>
<value key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName" type="QString">Make</value>
<value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString"></value>
<value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">CMakeProjectManager.MakeStep</value>
</valuemap>
<value key="ProjectExplorer.BuildStepList.StepsCount" type="int">1</value>
<value key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName" type="QString">Clean</value>
<value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString"></value>
<value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value key="ProjectExplorer.BuildConfiguration.BuildStepListCount" type="int">2</value>
<value key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment" type="bool">false</value>
<valuelist key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges" type="QVariantList"/>
<value key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName" type="QString">all</value>
<value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString"></value>
<value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">CMakeProjectManager.CMakeBuildConfiguration</value>
</valuemap>
<value key="ProjectExplorer.Target.BuildConfigurationCount" type="int">1</value>
<valuemap key="ProjectExplorer.Target.DeployConfiguration.0" type="QVariantMap">
<valuemap key="ProjectExplorer.BuildConfiguration.BuildStepList.0" type="QVariantMap">
<value key="ProjectExplorer.BuildStepList.StepsCount" type="int">0</value>
<value key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName" type="QString">Deploy</value>
<value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString"></value>
<value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">ProjectExplorer.BuildSteps.Deploy</value>
</valuemap>
<value key="ProjectExplorer.BuildConfiguration.BuildStepListCount" type="int">1</value>
<value key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName" type="QString">No deployment</value>
<value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString"></value>
<value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">ProjectExplorer.DefaultDeployConfiguration</value>
</valuemap>
<value key="ProjectExplorer.Target.DeployConfigurationCount" type="int">1</value>
<valuemap key="ProjectExplorer.Target.RunConfiguration.0" type="QVariantMap">
<valuelist key="Analyzer.Valgrind.AddedSupressionFiles" type="QVariantList"/>
<value key="Analyzer.Valgrind.FilterExternalIssues" type="bool">true</value>
<value key="Analyzer.Valgrind.NumCallers" type="int">25</value>
<valuelist key="Analyzer.Valgrind.RemovedSupressionFiles" type="QVariantList"/>
<value key="Analyzer.Valgrind.TrackOrigins" type="bool">true</value>
<value key="Analyzer.Valgrind.ValgrindExecutable" type="QString">valgrind</value>
<valuelist key="Analyzer.Valgrind.VisibleErrorKinds" type="QVariantList">
<value type="int">0</value>
<value type="int">1</value>
<value type="int">2</value>
<value type="int">3</value>
<value type="int">4</value>
<value type="int">5</value>
<value type="int">6</value>
<value type="int">7</value>
<value type="int">8</value>
<value type="int">9</value>
<value type="int">10</value>
<value type="int">11</value>
<value type="int">12</value>
<value type="int">13</value>
<value type="int">14</value>
</valuelist>
<value key="CMakeProjectManager.BaseEnvironmentBase" type="int">2</value>
<value key="CMakeProjectManager.CMakeRunConfiguation.Title" type="QString">tomahawk</value>
<value key="CMakeProjectManager.CMakeRunConfiguration.Arguments" type="QString">--verbose</value>
<value key="CMakeProjectManager.CMakeRunConfiguration.UseTerminal" type="bool">false</value>
<valuelist key="CMakeProjectManager.CMakeRunConfiguration.UserEnvironmentChanges" type="QVariantList">
<value type="QString">Q_FATAL_WARNINGS=1</value>
</valuelist>
<value key="CMakeProjectManager.CMakeRunConfiguration.UserWorkingDirectory" type="QString"></value>
<value key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName" type="QString">tomahawk</value>
<value key="ProjectExplorer.ProjectConfiguration.DisplayName" type="QString"></value>
<value key="ProjectExplorer.ProjectConfiguration.Id" type="QString">CMakeProjectManager.CMakeRunConfiguration.</value>
<value key="RunConfiguration.QmlDebugServerPort" type="uint">3768</value>
<value key="RunConfiguration.UseCppDebugger" type="bool">true</value>
<value key="RunConfiguration.UseQmlDebugger" type="bool">false</value>
</valuemap>
<value key="ProjectExplorer.Target.RunConfigurationCount" type="int">1</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.TargetCount</variable>
<value type="int">1</value>
</data>
<data>
<variable>ProjectExplorer.Project.Updater.EnvironmentId</variable>
<value type="QString">{6caf061d-47d5-4e4f-a8d8-0d83c14e4267}</value>
</data>
<data>
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
<value type="int">9</value>
</data>
</qtcreator>

View File

@@ -0,0 +1,139 @@
import QtQuick 1.1
Rectangle {
color: "black"
anchors.fill: parent
// height: 200
// width: 200
Component {
id: pathDelegate
Item {
width: 100; height: 100
scale: PathView.iconScale
// TODO: Use Image provider here
Image {
id: originalImage
width: 80
height: 80
source: index % 2 === 0 ? "http://www.muktware.com/sites/default/files/images/applications/tomahawk_icon.png" : "http://cloud.ohloh.net/attachments/53867/tomahawk-icon-64x64_med.png"
}
// mirror image - album art and a gradient filled rectangle for darkening
Item {
width: originalImage.width; height: originalImage.height
anchors.horizontalCenter: originalImage.horizontalCenter
// transform this item (the image and rectangle) to create the
// mirror image using the values from the Path
transform : [
Rotation {
angle: 180; origin.y: originalImage.height
axis.x: 1; axis.y: 0; axis.z: 0
},
Rotation {
angle: PathView.rotateY; origin.x: originalImage.width/2
axis.x: 0; axis.y: 1; axis.z: 0
},
Scale {
xScale: PathView.scaleArt; yScale: PathView.scaleArt
origin.x: originalImage.width/2; origin.y: originalImage.height/2
}
]
// mirror image
Image {
width: originalImage.width; height: originalImage.height
source: originalImage.source
anchors.horizontalCenter: parent.horizontalCenter
}
// mirror image dimming gradient filled rectangle
Rectangle {
width: originalImage.width+4; height: originalImage.height
anchors.horizontalCenter: parent.horizontalCenter
gradient: Gradient {
// TODO: no clue how to get the RGB component of the container rectangle color
GradientStop { position: 1.0; color: Qt.rgba(0,0,0,0.4) }
GradientStop { position: 0.3; color: reflectionContainer.color }
}
}
}
Text {
anchors { top: myIcon.bottom; horizontalCenter: parent.horizontalCenter }
text: label
smooth: true
color: "white"
}
MouseArea {
anchors.fill: parent
onClicked: view.currentIndex = index
}
}
}
PathView {
id: view
anchors { left: parent.left; top: parent.top; right: parent.right }
height: 300
preferredHighlightBegin: 0.5
preferredHighlightEnd: 0.5
focus: true
model: albumsModel
delegate: pathDelegate
pathItemCount: 8
path: Path {
startX: 10
startY: 50
PathAttribute { name: "iconScale"; value: 0.5 }
PathQuad { x: view.width/2; y: 150; controlX: 50; controlY: 200 }
PathAttribute { name: "iconScale"; value: 1.0 }
PathQuad { x: view.width; y: 50; controlX: view.width; controlY: 200 }
PathAttribute { name: "iconScale"; value: 0.5 }
}
}
Component {
id: gridDelegate
Item {
width: 100; height: 100
scale: PathView.iconScale
// TODO: Use Image provider here
Image {
id: originalImage
width: 80
height: 80
source: index % 2 === 0 ? "http://www.muktware.com/sites/default/files/images/applications/tomahawk_icon.png" : "http://cloud.ohloh.net/attachments/53867/tomahawk-icon-64x64_med.png"
}
Text {
anchors { top: myIcon.bottom; horizontalCenter: parent.horizontalCenter }
text: label
smooth: true
color: "white"
}
MouseArea {
anchors.fill: parent
onClicked: view.currentIndex = index
}
}
}
GridView {
id: grid
anchors { left: parent.left; top: view.bottom; right: parent.right; bottom: parent.bottom }
model: albumsModel
delegate: gridDelegate
}
}

155
data/qml/CoverImage.qml Normal file
View File

@@ -0,0 +1,155 @@
import QtQuick 1.1
Item {
id: root
// Should the artist + track labels be painted
property bool showLabels: true
// Should the play button be painted on mouse hover?
property bool showPlayButton: false
// Should the mirror be painted?
property bool showMirror: false
// Labels & Cover
property string artistName
property string trackName
property string artworkId
onArtworkIdChanged: print("!*!*!*!*!* artworkId", artworkId)
// The border color for the cover image
property color borderColor: "black"
// The border width for the cover image
property int borderWidth: 2
// needed to adjust the shadow
property color backgroundColor: "black"
// sets the brightness for the item and its mirror (1: brightest, 0: darkest)
property double itemBrightness: 1
property double mirrorBrightness: .5
// will be emitted when the on hower play button is clicked
signal playClicked()
// will be emitted when the cover is clicked
signal clicked()
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: root.clicked();
}
Component {
id: coverImage
Rectangle {
color: "white"
border.color: borderColor
border.width: borderWidth
Image {
anchors.fill: parent
//anchors.margins: borderWidth
source: "image://albumart/" + artworkId
}
Rectangle {
id: textBackground
anchors { left: parent.left; right: parent.right; bottom: parent.bottom }
height: 32
anchors.margins: 5
color: "black"
opacity: showLabels ? 0.5 : 0
radius: 3
}
Text {
color: "white"
font.bold: true
text: trackName
anchors { left: textBackground.left; right: textBackground.right; top: textBackground.top }
anchors.margins: 2
horizontalAlignment: Text.AlignHCenter
elide: Text.ElideRight
opacity: showLabels ? 1 : 0
}
Text {
color: "white"
text: artistName
anchors { left: textBackground.left; right: textBackground.right; bottom: textBackground.bottom }
anchors.margins: 2
horizontalAlignment: Text.AlignHCenter
elide: Text.ElideRight
opacity: showLabels ? 1 : 0
}
}
}
Loader {
sourceComponent: coverImage
anchors.fill: parent
}
Loader {
id: mirroredCover
sourceComponent: parent.showMirror ? coverImage : undefined
anchors.fill: parent
transform : [
Rotation {
angle: 180; origin.y: root.height
axis.x: 1; axis.y: 0; axis.z: 0
}
]
}
Rectangle {
id: itemShadow
color: backgroundColor
anchors.fill: parent
anchors.bottomMargin: - parent.height
// scaling might be off a pixel... make sure that the shadow is at least as large as the image
anchors.leftMargin: -2
anchors.rightMargin: -2
anchors.topMargin: -2
opacity: 1 - itemBrightness + (mouseArea.containsMouse ? .2 : 0)
Behavior on opacity {
NumberAnimation { easing.type: Easing.Linear; duration: 300 }
}
}
Rectangle {
id: mirrorShadow
color: parent.backgroundColor
height: parent.height + 2
width: parent.width + 4
anchors.centerIn: parent
anchors.verticalCenterOffset: parent.height
gradient: Gradient {
// TODO: no clue how to get the RGB component of the container rectangle color
// For now the Qt.rgba needs to be manually updated to match the backgroundColor
GradientStop { position: 0.0; color: Qt.rgba(0, 0, 0, 1-mirrorBrightness) }
GradientStop { position: 0.5; color: backgroundColor }
}
}
Image {
id: playButton
visible: showPlayButton ? mouseArea.containsMouse : false
source: "../images/play-rest.png"
anchors.centerIn: parent
MouseArea {
anchors.fill: parent
onClicked: root.playClicked();
}
}
}

View File

@@ -0,0 +1,79 @@
import QtQuick 1.1
import tomahawk 1.0
import "tomahawkimports"
Item {
id: fineTuneView
property color textColor: "white"
signal done();
Grid {
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.margins: 50
anchors.horizontalCenter: parent.horizontalCenter
width: scene.width / 2
spacing: 50
columns: 2
Text {
color: fineTuneView.textColor
text: "Name:"
}
InputField {
text: echonestStation.name
onAccepted: {
print("text changed!!!")
echonestStation.name = text;
}
}
Text {
id: tempoText
text: "Tempo:"
color: "white"
}
DoubleSlider {
width: 500
height: tempoText.height
min: 0
max: 500
lowerSliderPos: echonestStation.minTempo
upperSliderPos: echonestStation.maxTempo
onValueChanged: echonestStation.setTempo( lowerSliderPos, upperSliderPos )
}
Text {
id: hotnessText
text: "Hotness:"
color: "white"
}
DoubleSlider {
width: 500
height: hotnessText.height
min: 0
max: 100
minLabel: "Less"
maxLabel: "More"
showFloatingLabel: false
lowerSliderPos: echonestStation.minHotttness * 100
upperSliderPos: echonestStation.maxHotttness * 100
onValueChanged: echonestStation.setHotttness( 1.0 * lowerSliderPos / 100, 1.0 * upperSliderPos / 100 )
}
}
Button {
id: configureButton
onClicked: fineTuneView.done();
text: "configure"
anchors.bottom: parent.bottom
anchors.bottomMargin: 20
anchors.horizontalCenter: parent.horizontalCenter
}
}

158
data/qml/StationScene.qml Normal file
View File

@@ -0,0 +1,158 @@
import QtQuick 1.1
import tomahawk 1.0
import "tomahawkimports"
Rectangle {
id: scene
color: "black"
anchors.fill: parent
state: echonestStation.configured ? "list" : "configure"
ListModel {
id: styleModel
ListElement { modelData: "acoustic" }
ListElement { modelData: "alternative" }
ListElement { modelData: "alternative rock" }
ListElement { modelData: "classic" }
ListElement { modelData: "folk" }
ListElement { modelData: "indie" }
ListElement { modelData: "pop" }
ListElement { modelData: "rock" }
ListElement { modelData: "hip-hop" }
ListElement { modelData: "punk" }
ListElement { modelData: "grunge" }
ListElement { modelData: "indie" }
ListElement { modelData: "electronic" }
ListElement { modelData: "country" }
ListElement { modelData: "jazz" }
ListElement { modelData: "psychodelic" }
ListElement { modelData: "soundtrack" }
ListElement { modelData: "reggae" }
ListElement { modelData: "house" }
ListElement { modelData: "drum and base" }
}
ListModel {
id: dummyArtistModel
ListElement { modelData: "Pink Floyd" }
ListElement { modelData: "Tool" }
ListElement { modelData: "Cake" }
ListElement { modelData: "Metallica" }
ListElement { modelData: "Red Hot Chili Peppers" }
ListElement { modelData: "Korn" }
ListElement { modelData: "Prodigy" }
ListElement { modelData: "Otto Waalkes" }
}
VisualItemModel {
id: stationVisualModel
Column {
height: scene.height
width: scene.width
Row {
height: scene.height / 2
width: scene.width
spacing: width * .1
Item {
height: parent.height
width: (parent.width - orText.width - parent.spacing * 2 ) * 2 / 3
GridView {
id: gridView
anchors.fill: parent
anchors.margins: cellWidth / 2
model: dummyArtistModel
cellWidth: gridView.width / 4 - 1 // -1 to make sure there is space for 4 items even with rounding error
cellHeight: cellWidth
delegate: Item {
height: gridView.cellHeight * .9
width: height
CoverImage {
artistName: modelData
anchors.fill: parent
onClicked: {
echonestStation.setMainControl( EchonestStation.StationTypeArtist, modelData );
stationListView.incrementCurrentIndex();
}
}
}
}
}
}
Row {
height: scene.height / 2
width: scene.width * .9
anchors.horizontalCenter: parent.horizontalCenter
spacing: width * .1
TagCloud {
height: parent.height
width: (parent.width - orText.width - parent.spacing * 2 ) * 2 / 3
model: styleModel//generator.styles()
opacity: echonestStation.configured ? 0 : 1
onTagClicked: {
echonestStation.setMainControl( EchonestStation.StationTypeStyle, item );
stationListView.incrementCurrentIndex();
}
Behavior on opacity {
NumberAnimation { duration: 300 }
}
}
Text {
id: orText
text: "or"
color: "white"
anchors.verticalCenter: parent.verticalCenter
}
InputField {
anchors.verticalCenter: parent.verticalCenter
width: (parent.width - orText.width - parent.spacing * 2 ) * 1 / 3
}
}
}
StationView {
coverSize: Math.min(scene.height, scene.width) / 2
height: scene.height
width: scene.width
onConfigure: stationListView.incrementCurrentIndex();
}
StationConfig {
height: scene.height
width: scene.width
onDone: stationListView.decrementCurrentIndex();
}
}
ListView {
id: stationListView
anchors.fill: parent
contentHeight: scene.height
contentWidth: scene.width
orientation: ListView.Horizontal
model: stationVisualModel
interactive: false
highlightMoveDuration: 400
Component.onCompleted: {
if ( echonestStation.configured ) {
currentIndex = 1
}
}
}
}

188
data/qml/StationView.qml Normal file
View File

@@ -0,0 +1,188 @@
import QtQuick 1.1
import tomahawk 1.0
import "tomahawkimports"
Item {
id: root
property int coverSize
signal configure()
PathView {
id: coverView
anchors.fill: parent
anchors.rightMargin: parent.width / 3
preferredHighlightBegin: 0.2 // scene.width / 11000
preferredHighlightEnd: preferredHighlightBegin
pathItemCount: 5
//highlightMoveDuration: 500
model: dynamicModel
currentIndex: currentlyPlayedIndex
property int pathStartX: width / 2
property int pathStartY: height / 2
delegate: CoverImage {
height: root.coverSize
width: root.coverSize
showLabels: false
showMirror: true
//artistName: model.artistName
//trackName: model.trackName
artworkId: model.coverID
scale: PathView.itemScale
itemBrightness: PathView.itemBrightness
opacity: PathView.itemOpacity
z: x
onClicked: {
if ( currentlyPlayedIndex !==-1 ) {
echonestStation.playItem( index )
}
}
}
path: Path {
startX: coverView.pathStartX
startY: coverView.pathStartY
PathAttribute { name: "itemOpacity"; value: 0 }
PathAttribute { name: "itemBrightness"; value: 0 }
PathAttribute { name: "itemScale"; value: 1.5 }
PathLine { x: coverView.pathStartX * 0.9 ; y: coverView.pathStartY * 0.9 }
PathPercent { value: .2 }
PathAttribute { name: "itemOpacity"; value: 1 }
PathAttribute { name: "itemBrightness"; value: 1 }
PathAttribute { name: "itemScale"; value: 1 }
PathLine { x: coverView.pathStartX * .5; y: coverView.pathStartY * .5}
PathPercent { value: .3 }
PathAttribute { name: "itemOpacity"; value: 1 }
PathAttribute { name: "itemBrightness"; value: 1 }
PathAttribute { name: "itemScale"; value: 0.5 }
// PathLine { x: coverView.pathStartX * .25 ; y: coverView.pathStartY * .25 }
// PathPercent { value: .75 }
// PathAttribute { name: "itemOpacity"; value: 1 }
// PathAttribute { name: "itemBrightness"; value: .5 }
// PathAttribute { name: "itemScale"; value: 0.4 }
PathLine { x: 0; y: 0 }
PathPercent { value: 1 }
PathAttribute { name: "itemOpacity"; value: 1 }
PathAttribute { name: "itemBrightness"; value: 0 }
PathAttribute { name: "itemScale"; value: 0.1 }
}
}
Item {
anchors { top: parent.top; right: parent.right; bottom: parent.bottom }
anchors.margins: 50
width: scene.width / 3
Column {
anchors { left: parent.left; top: parent.top; right: parent.right }
Text {
color: "white"
font.pointSize: 12
width: parent.width
elide: Text.ElideRight
text: "Station:"
}
Text {
color: "white"
font.pointSize: 14
font.bold: true
width: parent.width
elide: Text.ElideRight
text: echonestStation.name
}
}
Column {
anchors.right: parent.right
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
width: scene.width / 3
Text {
color: "white"
font.pointSize: 12
width: parent.width
elide: Text.ElideRight
text: "Now Playing:"
visible: currentlyPlayedIndex !== -1
}
Rectangle {
height: image.height + image.height / 5
width: image.width + startPlayingText.width * 1.2
radius: height / 2
border.width: 2
border.color: "white"
color: startPlayingMouseArea.containsMouse ? "blue" : "gray"
visible: currentlyPlayedIndex === -1
Image {
id: image
source: "../images/play-rest.png"
anchors.left: parent.left
anchors.margins: 10
anchors.verticalCenter: parent.verticalCenter
}
Text {
id: startPlayingText
color: "white"
font.pointSize: 20
anchors.left: image.right
anchors.margins: height / 5
anchors.verticalCenter: parent.verticalCenter
//width: parent.width - 30 - image.width
elide: Text.ElideRight
text: "Start playing"
}
MouseArea {
id: startPlayingMouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: echonestStation.playItem( 0 );
}
}
Text {
color: "white"
font.pointSize: 16
width: parent.width
elide: Text.ElideRight
text: currentlyPlayedIndex > -1 ? coverView.model.itemFromIndex( currentlyPlayedIndex ).name : ""
}
Text {
color: "white"
font.pointSize: 14
width: parent.width
elide: Text.ElideRight
text: currentlyPlayedIndex > -1 ? coverView.model.itemFromIndex( currentlyPlayedIndex ).artistName : ""
}
Text {
color: "white"
font.pointSize: 14
width: parent.width
elide: Text.ElideRight
text: currentlyPlayedIndex > -1 ? coverView.model.itemFromIndex( currentlyPlayedIndex ).albumName : ""
}
}
}
Button {
id: configureButton
anchors.bottom: parent.bottom
anchors.bottomMargin: 20
anchors.horizontalCenter: parent.horizontalCenter
text: "configure"
onClicked: root.configure();
}
}

53
data/qml/TagCloud.qml Normal file
View File

@@ -0,0 +1,53 @@
import QtQuick 1.1
import tomahawk 1.0
Item {
id: tagCloud
property variant model: 10
signal tagClicked( string item )
function randomNumber(min, max) {
var date = new Date();
return (max - min) * Math.random(date.getSeconds()) + min
}
Flow {
anchors.centerIn: parent
width: parent.width
spacing: 3
Repeater {
id: cloudRepeater
model: tagCloud.model
delegate: Item {
id: cloudItem
width: delegateText.width * 1.1
height: delegateText.height
property double itemScale: Math.random() + .3
scale: itemScale
Text {
id: delegateText
color: "white"
//text: controlModel.controlAt( index ).summary
text: modelData
font.pointSize: 16
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: tagCloud.randomNumber(0, 15)
}
MouseArea {
hoverEnabled: true
anchors.fill: parent
onClicked: tagCloud.tagClicked( modelData )
}
Behavior on scale {
NumberAnimation { easing: Easing.Linear; duration: 1000 }
}
}
}
}
}

View File

@@ -0,0 +1,29 @@
import QtQuick 1.1
Rectangle {
id: root
color: buttonMouseArea.containsMouse ? "blue" : "gray"
border.width: 2
border.color: "white"
radius: height/2
height: buttonText.height * 1.2
width: buttonText.width * 1.5
property alias text: buttonText.text
property color textColor: "white"
signal clicked()
Text {
id: buttonText
anchors.centerIn: parent
color: root.textColor
}
MouseArea {
id: buttonMouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: root.clicked();
}
}

View File

@@ -0,0 +1,151 @@
import QtQuick 1.1
Item {
id: root
width: 500
height: 10
property int min: 0
property int max: 100
/** The labels next to the slider
* if empty, min and max values are used
*/
property string minLabel: ""
property string maxLabel: ""
/** Should the floating label indicating the current position be shown? */
property bool showFloatingLabel: true
property int lowerSliderPos: 25
property int upperSliderPos: 75
signal valueChanged()
Row {
anchors.fill: parent
spacing: 10
Text {
id: minText
text: root.minLabel.length > 0 ? root.minLabel : min
color: "white"
}
Item {
id: sliderRect
height: root.height
width: parent.width - minText.width - maxText.width - parent.spacing * 2
function sliderPosToValue( sliderPos ) {
var percent = sliderPos * 100 / (sliderRect.width - lowerSlider.width);
return Math.floor(percent * (root.max - root.min) / 100) + root.min
}
function valueToSloderPos( value ) {
var percent = (value - root.min) * 100 / (root.max - root.min)
return percent * (sliderRect.width - lowerSlider.width) / 100
}
Rectangle {
id: sliderBase
height: root.height / 5
width: parent.width
color: "white"
radius: height / 2
anchors.centerIn: parent
}
Rectangle {
id: lowerSlider
height: root.height
width: height
anchors.top: root.top
radius: height/2
border.color: "black"
border.width: 2
x: sliderRect.valueToSloderPos(root.lowerSliderPos)
Rectangle {
id: lowerFloatingRect
color: "white"
anchors.bottom: lowerSlider.top
anchors.bottomMargin: 10
visible: root.showFloatingLabel && lowerSliderMouseArea.pressed
width: lowerFloatingText.width * 1.2
height: lowerFloatingText.height + height * 1.2
x: -(width - lowerSlider.width) / 2
radius: height / 4
Text {
id: lowerFloatingText
anchors.centerIn: parent
text: sliderRect.sliderPosToValue(lowerSlider.x)
}
}
}
MouseArea {
id: lowerSliderMouseArea
anchors.fill: lowerSlider
drag.target: lowerSlider
drag.axis: "XAxis"
drag.minimumX: 0
drag.maximumX: upperSlider.x - lowerSlider.width
onReleased: {
root.lowerSliderPos = sliderRect.sliderPosToValue( lowerSlider.x );
root.valueChanged();
}
}
Rectangle {
id: upperSlider
height: root.height
width: height
anchors.top: root.top
radius: height/2
border.color: "black"
border.width: 2
x: sliderRect.valueToSloderPos(root.upperSliderPos)
Rectangle {
id: upperFloatingRect
color: "white"
anchors.bottom: upperSlider.top
anchors.bottomMargin: 10
visible: root.showFloatingLabel && upperSliderMouseArea.pressed
width: upperFloatingText.width * 1.2
height: upperFloatingText.height + height * 1.2
radius: height / 4
x: -(width - upperSlider.width) / 2
Text {
id: upperFloatingText
anchors.centerIn: parent
text: sliderRect.sliderPosToValue(upperSlider.x)
}
}
}
MouseArea {
id: upperSliderMouseArea
anchors.fill: upperSlider
onClicked: print("button pressed")
drag.target: upperSlider
drag.axis: "XAxis"
drag.minimumX: lowerSlider.x + lowerSlider.width
drag.maximumX: parent.width - upperSlider.width
onReleased: {
root.upperSliderPos = sliderRect.sliderPosToValue( upperSlider.x );
root.valueChanged();
}
}
}
Text {
id: maxText
text: root.maxLabel.length > 0 ? root.maxLabel : max
color: "white"
}
}
}

View File

@@ -0,0 +1,23 @@
import QtQuick 1.1
Rectangle {
id: root
color: "white"
border.color: "black"
border.width: 2
height: textInput.height + 4
width: 300
property alias text: textInput.text
signal accepted( string text )
TextInput {
id: textInput
width: parent.width
anchors.centerIn: parent
onAccepted: root.accepted( text );
}
}

View File

@@ -150,5 +150,14 @@
<file>data/images/scrollbar-horizontal-handle.png</file>
<file>data/images/subscribe-on.png</file>
<file>data/images/subscribe-off.png</file>
<file>data/qml/ArtistInfoScene.qml</file>
<file>data/qml/StationScene.qml</file>
<file>data/qml/CoverImage.qml</file>
<file>data/qml/TagCloud.qml</file>
<file>data/qml/StationConfig.qml</file>
<file>data/qml/StationView.qml</file>
<file>data/qml/tomahawkimports/InputField.qml</file>
<file>data/qml/tomahawkimports/Button.qml</file>
<file>data/qml/tomahawkimports/DoubleSlider.qml</file>
</qresource>
</RCC>

View File

@@ -35,19 +35,11 @@ using namespace Tomahawk;
QHash< QString, album_ptr > Album::s_albumsByName = QHash< QString, album_ptr >();
QHash< unsigned int, album_ptr > Album::s_albumsById = QHash< unsigned int, album_ptr >();
QHash< QString, album_ptr > Album::s_albumsByCoverId = QHash< QString, album_ptr >();
static QMutex s_nameCacheMutex;
static QMutex s_idCacheMutex;
static QMutex s_mutex;
static QReadWriteLock s_idMutex;
Album::~Album()
{
m_ownRef.clear();
#ifndef ENABLE_HEADLESS
delete m_cover;
#endif
}
inline QString
albumCacheKey( const Tomahawk::artist_ptr& artist, const QString& albumName )
@@ -62,7 +54,7 @@ Album::get( const Tomahawk::artist_ptr& artist, const QString& name, bool autoCr
if ( !Database::instance() || !Database::instance()->impl() )
return album_ptr();
QMutexLocker l( &s_nameCacheMutex );
QMutexLocker l( &s_mutex );
const QString key = albumCacheKey( artist, name );
if ( s_albumsByName.contains( key ) )
@@ -75,6 +67,7 @@ Album::get( const Tomahawk::artist_ptr& artist, const QString& name, bool autoCr
album->setWeakRef( album.toWeakRef() );
album->loadId( autoCreate );
s_albumsByCoverId[ album->coverId() ] = album;
s_albumsByName[ key ] = album;
return album;
@@ -85,9 +78,8 @@ album_ptr
Album::get( unsigned int id, const QString& name, const Tomahawk::artist_ptr& artist )
{
static QHash< unsigned int, album_ptr > s_albums;
static QMutex s_mutex;
QMutexLocker lock( &s_idCacheMutex );
QMutexLocker lock( &s_mutex );
if ( s_albumsById.contains( id ) )
{
return s_albumsById.value( id );
@@ -96,6 +88,8 @@ Album::get( unsigned int id, const QString& name, const Tomahawk::artist_ptr& ar
album_ptr a = album_ptr( new Album( id, name, artist ), &QObject::deleteLater );
a->setWeakRef( a.toWeakRef() );
s_albumsByCoverId[ a->coverId() ] = a;
s_albumsByName[ albumCacheKey( artist, name ) ] = a;
if ( id > 0 )
s_albumsById.insert( id, a );
@@ -103,6 +97,18 @@ Album::get( unsigned int id, const QString& name, const Tomahawk::artist_ptr& ar
}
album_ptr
Album::getByCoverId( const QString& uuid )
{
QMutexLocker lock( &s_mutex );
if ( s_albumsByCoverId.contains( uuid ) )
return s_albumsByCoverId.value( uuid );
return album_ptr();
}
Album::Album( unsigned int id, const QString& name, const Tomahawk::artist_ptr& artist )
: QObject()
, m_waitingForId( false )
@@ -133,6 +139,23 @@ Album::Album( const QString& name, const Tomahawk::artist_ptr& artist )
m_sortname = DatabaseImpl::sortname( name );
}
Album::~Album()
{
QMutexLocker lock( &s_mutex );
s_albumsByName.remove( albumCacheKey( artist(), name() ) );
s_albumsByCoverId.remove( coverId() );
/* if ( id() > 0 )
s_albumsById.remove( id() );*/
m_ownRef.clear();
#ifndef ENABLE_HEADLESS
delete m_cover;
#endif
}
void
Album::onTracksLoaded( Tomahawk::ModelMode mode, const Tomahawk::collection_ptr& collection )
{
@@ -179,9 +202,12 @@ Album::id() const
m_waitingForId = false;
if ( m_id > 0 )
{
QMutexLocker lock( &s_mutex );
s_albumsById[ m_id ] = m_ownRef.toStrongRef();
s_idMutex.unlock();
}
s_idMutex.unlock();
}
return finalId;
@@ -202,7 +228,7 @@ Album::cover( const QSize& size, bool forceLoad ) const
trackInfo["album"] = name();
Tomahawk::InfoSystem::InfoRequestData requestData;
requestData.caller = infoid();
requestData.caller = uniqueId();
requestData.type = Tomahawk::InfoSystem::InfoAlbumCoverArt;
requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( trackInfo );
requestData.customData = QVariantMap();
@@ -250,7 +276,7 @@ Album::cover( const QSize& size, bool forceLoad ) const
void
Album::infoSystemInfo( const Tomahawk::InfoSystem::InfoRequestData& requestData, const QVariant& output )
{
if ( requestData.caller != infoid() ||
if ( requestData.caller != uniqueId() ||
requestData.type != Tomahawk::InfoSystem::InfoAlbumCoverArt )
{
return;
@@ -269,7 +295,13 @@ Album::infoSystemInfo( const Tomahawk::InfoSystem::InfoRequestData& requestData,
m_coverBuffer = ba;
}
m_coverLoaded = true;
{
QMutexLocker lock( &s_mutex );
m_coverLoaded = true;
s_albumsByCoverId.remove( coverId() );
m_coverId = uuid();
s_albumsByCoverId[ m_coverId ] = m_ownRef.toStrongRef();
}
emit coverChanged();
}
}
@@ -278,7 +310,7 @@ Album::infoSystemInfo( const Tomahawk::InfoSystem::InfoRequestData& requestData,
void
Album::infoSystemFinished( const QString& target )
{
if ( target != infoid() )
if ( target != uniqueId() )
return;
disconnect( Tomahawk::InfoSystem::InfoSystem::instance(), SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
@@ -319,10 +351,20 @@ Album::tracks( ModelMode mode, const Tomahawk::collection_ptr& collection )
QString
Album::infoid() const
Album::uniqueId() const
{
if ( m_uuid.isEmpty() )
m_uuid = uuid();
return m_uuid;
}
QString
Album::coverId() const
{
if ( m_coverId.isEmpty() )
m_coverId = uuid();
return m_coverId;
}

View File

@@ -47,6 +47,7 @@ Q_OBJECT
public:
static album_ptr get( const Tomahawk::artist_ptr& artist, const QString& name, bool autoCreate = false );
static album_ptr get( unsigned int id, const QString& name, const Tomahawk::artist_ptr& artist );
static album_ptr getByCoverId( const QString& uuid );
Album( unsigned int id, const QString& name, const Tomahawk::artist_ptr& artist );
Album( const QString& name, const Tomahawk::artist_ptr& artist );
@@ -55,6 +56,8 @@ public:
unsigned int id() const;
QString name() const { return m_name; }
QString sortname() const { return m_sortname; }
QString uniqueId() const;
QString coverId() const;
artist_ptr artist() const;
#ifndef ENABLE_HEADLESS
@@ -82,7 +85,6 @@ private slots:
private:
Q_DISABLE_COPY( Album )
QString infoid() const;
void setIdFuture( QFuture<unsigned int> future );
mutable bool m_waitingForId;
@@ -97,6 +99,7 @@ private:
bool m_coverLoaded;
mutable bool m_coverLoading;
mutable QString m_uuid;
mutable QString m_coverId;
#ifndef ENABLE_HEADLESS
mutable QPixmap* m_cover;
@@ -109,6 +112,7 @@ private:
static QHash< QString, album_ptr > s_albumsByName;
static QHash< unsigned int, album_ptr > s_albumsById;
static QHash< QString, album_ptr > s_albumsByCoverId;
friend class ::IdThreadWorker;
};

View File

@@ -38,20 +38,11 @@ using namespace Tomahawk;
QHash< QString, artist_ptr > Artist::s_artistsByName = QHash< QString, artist_ptr >();
QHash< unsigned int, artist_ptr > Artist::s_artistsById = QHash< unsigned int, artist_ptr >();
QHash< QString, artist_ptr > Artist::s_artistsByCoverId = QHash< QString, artist_ptr >();
static QMutex s_nameCacheMutex;
static QMutex s_idCacheMutex;
static QMutex s_mutex;
static QReadWriteLock s_idMutex;
Artist::~Artist()
{
m_ownRef.clear();
#ifndef ENABLE_HEADLESS
delete m_cover;
#endif
}
artist_ptr
Artist::get( const QString& name, bool autoCreate )
@@ -59,7 +50,7 @@ Artist::get( const QString& name, bool autoCreate )
if ( name.isEmpty() )
return artist_ptr();
QMutexLocker lock( &s_nameCacheMutex );
QMutexLocker lock( &s_mutex );
if ( s_artistsByName.contains( name ) )
return s_artistsByName.value( name );
@@ -73,6 +64,7 @@ Artist::get( const QString& name, bool autoCreate )
artist->setWeakRef( artist.toWeakRef() );
artist->loadId( autoCreate );
s_artistsByCoverId[ artist->coverId() ] = artist;
s_artistsByName[ name ] = artist;
return artist;
@@ -82,7 +74,7 @@ Artist::get( const QString& name, bool autoCreate )
artist_ptr
Artist::get( unsigned int id, const QString& name )
{
QMutexLocker lock( &s_idCacheMutex );
QMutexLocker lock( &s_mutex );
if ( s_artistsById.contains( id ) )
{
return s_artistsById.value( id );
@@ -91,6 +83,8 @@ Artist::get( unsigned int id, const QString& name )
artist_ptr a = artist_ptr( new Artist( id, name ), &QObject::deleteLater );
a->setWeakRef( a.toWeakRef() );
s_artistsByCoverId[ a->coverId() ] = a;
s_artistsByName[ name ] = a;
if ( id > 0 )
s_artistsById.insert( id, a );
@@ -98,6 +92,18 @@ Artist::get( unsigned int id, const QString& name )
}
artist_ptr
Artist::getByCoverId( const QString& uuid )
{
QMutexLocker lock( &s_mutex );
if ( s_artistsByCoverId.contains( uuid ) )
return s_artistsByCoverId.value( uuid );
return artist_ptr();
}
Artist::Artist( unsigned int id, const QString& name )
: QObject()
, m_waitingForFuture( false )
@@ -134,6 +140,22 @@ Artist::Artist( const QString& name )
}
Artist::~Artist()
{
QMutexLocker lock( &s_mutex );
s_artistsByName.remove( name() );
s_artistsByCoverId.remove( coverId() );
/* if ( id() > 0 )
s_artistsById.remove( id() );*/
m_ownRef.clear();
#ifndef ENABLE_HEADLESS
delete m_cover;
#endif
}
void
Artist::onTracksLoaded( Tomahawk::ModelMode mode, const Tomahawk::collection_ptr& collection )
{
@@ -168,7 +190,7 @@ Artist::albums( ModelMode mode, const Tomahawk::collection_ptr& collection ) con
artistInfo["artist"] = name();
Tomahawk::InfoSystem::InfoRequestData requestData;
requestData.caller = infoid();
requestData.caller = uniqueId();
requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( artistInfo );
requestData.type = Tomahawk::InfoSystem::InfoArtistReleases;
@@ -208,7 +230,7 @@ Artist::similarArtists() const
artistInfo["artist"] = name();
Tomahawk::InfoSystem::InfoRequestData requestData;
requestData.caller = infoid();
requestData.caller = uniqueId();
requestData.customData = QVariantMap();
requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( artistInfo );
@@ -276,7 +298,11 @@ Artist::id() const
m_waitingForFuture = false;
if ( m_id > 0 )
{
QMutexLocker lock( &s_mutex );
s_artistsById[ m_id ] = m_ownRef.toStrongRef();
}
s_idMutex.unlock();
}
@@ -290,7 +316,7 @@ Artist::biography() const
if ( !m_biographyLoaded )
{
Tomahawk::InfoSystem::InfoRequestData requestData;
requestData.caller = infoid();
requestData.caller = uniqueId();
requestData.customData = QVariantMap();
requestData.input = name();
@@ -378,7 +404,7 @@ Artist::onAlbumsFound( const QList< album_ptr >& albums, const QVariant& data )
void
Artist::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output )
{
if ( requestData.caller != infoid() )
if ( requestData.caller != uniqueId() )
return;
QVariantMap returnedData = output.value< QVariantMap >();
@@ -419,7 +445,13 @@ Artist::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVari
m_coverBuffer = ba;
}
m_coverLoaded = true;
{
QMutexLocker lock( &s_mutex );
m_coverLoaded = true;
s_artistsByCoverId.remove( coverId() );
m_coverId = uuid();
s_artistsByCoverId[ m_coverId ] = m_ownRef.toStrongRef();
}
emit coverChanged();
}
@@ -467,7 +499,7 @@ Artist::infoSystemFinished( QString target )
{
Q_UNUSED( target );
if ( target != infoid() )
if ( target != uniqueId() )
return;
if ( --m_infoJobs == 0 )
@@ -498,7 +530,7 @@ Artist::cover( const QSize& size, bool forceLoad ) const
trackInfo["artist"] = name();
Tomahawk::InfoSystem::InfoRequestData requestData;
requestData.caller = infoid();
requestData.caller = uniqueId();
requestData.type = Tomahawk::InfoSystem::InfoArtistImages;
requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( trackInfo );
requestData.customData = QVariantMap();
@@ -571,10 +603,20 @@ Artist::tracks( ModelMode mode, const Tomahawk::collection_ptr& collection )
QString
Artist::infoid() const
Artist::uniqueId() const
{
if ( m_uuid.isEmpty() )
m_uuid = uuid();
return m_uuid;
}
QString
Artist::coverId() const
{
if ( m_coverId.isEmpty() )
m_coverId = uuid();
return m_coverId;
}

View File

@@ -46,6 +46,7 @@ Q_OBJECT
public:
static artist_ptr get( const QString& name, bool autoCreate = false );
static artist_ptr get( unsigned int id, const QString& name );
static artist_ptr getByCoverId( const QString& uuid );
Artist( unsigned int id, const QString& name );
explicit Artist( const QString& name );
@@ -54,6 +55,8 @@ public:
unsigned int id() const;
QString name() const { return m_name; }
QString sortname() const { return m_sortname; }
QString uniqueId() const;
QString coverId() const;
QList<Tomahawk::album_ptr> albums( ModelMode mode = Mixed, const Tomahawk::collection_ptr& collection = Tomahawk::collection_ptr() ) const;
QList<Tomahawk::artist_ptr> similarArtists() const;
@@ -65,7 +68,7 @@ public:
QList< Tomahawk::PlaybackLog > playbackHistory( const Tomahawk::source_ptr& source = Tomahawk::source_ptr() ) const;
void setPlaybackHistory( const QList< Tomahawk::PlaybackLog >& playbackData );
unsigned int playbackCount( const Tomahawk::source_ptr& source = Tomahawk::source_ptr() );
QString biography() const;
#ifndef ENABLE_HEADLESS
@@ -98,7 +101,6 @@ private slots:
private:
Artist();
QString infoid() const;
void setIdFuture( QFuture<unsigned int> idFuture );
@@ -116,6 +118,7 @@ private:
bool m_biographyLoaded;
mutable QString m_uuid;
mutable QString m_coverId;
mutable int m_infoJobs;
QList<Tomahawk::album_ptr> m_databaseAlbums;
@@ -133,11 +136,12 @@ private:
#endif
QHash< Tomahawk::ModelMode, QHash< Tomahawk::collection_ptr, Tomahawk::playlistinterface_ptr > > m_playlistInterface;
QWeakPointer< Tomahawk::Artist > m_ownRef;
static QHash< QString, artist_ptr > s_artistsByName;
static QHash< unsigned int, artist_ptr > s_artistsById;
static QHash< QString, artist_ptr > s_artistsByCoverId;
friend class ::IdThreadWorker;
};

View File

@@ -82,7 +82,9 @@ set( libGuiSources
playlist/dynamic/echonest/EchonestGenerator.cpp
playlist/dynamic/echonest/EchonestControl.cpp
playlist/dynamic/echonest/EchonestSteerer.cpp
playlist/dynamic/echonest/EchonestStation.cpp
playlist/dynamic/widgets/DynamicWidget.cpp
playlist/dynamic/widgets/DynamicQmlWidget.cpp
playlist/dynamic/widgets/DynamicControlWrapper.cpp
playlist/dynamic/widgets/DynamicControlList.cpp
playlist/dynamic/widgets/ReadOrWriteWidget.cpp
@@ -140,11 +142,13 @@ set( libGuiSources
widgets/ToggleButton.cpp
widgets/FadingPixmap.cpp
widgets/SocialPlaylistWidget.cpp
widgets/DeclarativeCoverArtProvider.cpp
widgets/SourceTreePopupDialog.cpp
widgets/infowidgets/SourceInfoWidget.cpp
widgets/infowidgets/ArtistInfoWidget.cpp
widgets/infowidgets/AlbumInfoWidget.cpp
widgets/infowidgets/TrackInfoWidget.cpp
widgets/infowidgets/AlbumArtImageProvider.cpp
widgets/searchlineedit/ClearButton.cpp
widgets/searchlineedit/LineEdit.cpp
widgets/searchlineedit/SearchButton.cpp
@@ -456,6 +460,7 @@ TARGET_LINK_LIBRARIES( tomahawklib
${QT_QTNETWORK_LIBRARY}
${QT_QTXML_LIBRARY}
${QT_QTCORE_LIBRARY}
${QT_QTDECLARATIVE_LIBRARY}
${OS_SPECIFIC_LINK_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT}
${LINK_LIBRARIES}

View File

@@ -82,8 +82,11 @@ PlaybackLog::PlaybackLog( const PlaybackLog& other )
query_ptr
Query::get( const QString& artist, const QString& track, const QString& album, const QID& qid, bool autoResolve )
{
if ( artist.trimmed().isEmpty() || track.trimmed().isEmpty() )
if ( artist.trimmed().isEmpty() || track.trimmed().isEmpty() )
{
Q_ASSERT( false );
return query_ptr();
}
if ( qid.isEmpty() )
autoResolve = false;
@@ -150,6 +153,7 @@ Query::Query( const QString& query, const QID& qid )
Query::~Query()
{
QMutexLocker lock( &m_mutex );
m_ownRef.clear();
m_results.clear();
}
@@ -349,6 +353,22 @@ Query::id() const
}
QString
Query::coverId() const
{
if ( m_albumPtr && m_albumPtr->coverLoaded() && !m_albumPtr->cover( QSize( 0, 0 ) ).isNull() )
{
return m_albumPtr->coverId();
}
else if ( m_artistPtr )
{
return m_artistPtr->coverId();
}
return QString();
}
void
Query::setPlayedBy( const Tomahawk::source_ptr& source, unsigned int playtime )
{

View File

@@ -95,6 +95,7 @@ public:
unsigned int numResults() const;
QID id() const;
QString coverId() const;
/// sorter for list of results
static bool resultSorter( const result_ptr& left, const result_ptr& right );

View File

@@ -42,6 +42,7 @@
#include "PlaylistLargeItemDelegate.h"
#include "RecentlyPlayedModel.h"
#include "dynamic/widgets/DynamicWidget.h"
#include "dynamic/widgets/DynamicQmlWidget.h"
#include "widgets/NewReleasesWidget.h"
#include "widgets/WelcomeWidget.h"
@@ -190,7 +191,7 @@ ViewManager::show( const Tomahawk::dynplaylist_ptr& playlist )
{
if ( !m_dynamicWidgets.contains( playlist ) || m_dynamicWidgets.value( playlist ).isNull() )
{
m_dynamicWidgets[ playlist ] = new Tomahawk::DynamicWidget( playlist, m_stack );
m_dynamicWidgets[ playlist ] = new Tomahawk::DynamicQmlWidget( playlist, m_stack );
playlist->resolve();
}
@@ -832,7 +833,7 @@ ViewManager::playlistForInterface( Tomahawk::playlistinterface_ptr interface ) c
Tomahawk::dynplaylist_ptr
ViewManager::dynamicPlaylistForInterface( Tomahawk::playlistinterface_ptr interface ) const
{
foreach ( QWeakPointer<DynamicWidget> view, m_dynamicWidgets.values() )
foreach ( QWeakPointer<DynamicQmlWidget> view, m_dynamicWidgets.values() )
{
if ( !view.isNull() && view.data()->playlistInterface() == interface )
{

View File

@@ -59,6 +59,7 @@ class QPushButton;
namespace Tomahawk
{
class DynamicWidget;
class DynamicQmlWidget;
}
class DLLEXPORT ViewManager : public QObject
@@ -196,7 +197,7 @@ private:
QList< Tomahawk::collection_ptr > m_superCollections;
QHash< Tomahawk::dynplaylist_ptr, QWeakPointer<Tomahawk::DynamicWidget> > m_dynamicWidgets;
QHash< Tomahawk::dynplaylist_ptr, QWeakPointer<Tomahawk::DynamicQmlWidget> > m_dynamicWidgets;
QHash< Tomahawk::collection_ptr, QWeakPointer<TreeView> > m_treeViews;
QHash< Tomahawk::artist_ptr, QWeakPointer<ArtistInfoWidget> > m_artistViews;
QHash< Tomahawk::album_ptr, QWeakPointer<AlbumInfoWidget> > m_albumViews;

View File

@@ -520,19 +520,12 @@ LastFmInfoPlugin::notInCacheSlot( QHash<QString, QString> criteria, Tomahawk::In
QString artistName = criteria["artist"];
QString albumName = criteria["album"];
QUrl imgurl( "http://ws.audioscrobbler.com/2.0/" );
imgurl.addQueryItem( "method", "album.imageredirect" );
imgurl.addEncodedQueryItem( "artist", QUrl::toPercentEncoding( artistName, "", "+" ) );
imgurl.addEncodedQueryItem( "album", QUrl::toPercentEncoding( albumName, "", "+" ) );
imgurl.addQueryItem( "autocorrect", QString::number( 1 ) );
imgurl.addQueryItem( "size", "large" );
imgurl.addQueryItem( "api_key", "7a90f6672a04b809ee309af169f34b8b" );
lastfm::Artist lfmArtist( artistName );
lastfm::Album lfmAlbum( lfmArtist, albumName );
QNetworkRequest req( imgurl );
QNetworkReply* reply = TomahawkUtils::nam()->get( req );
QNetworkReply* reply = lfmAlbum.getInfo();
reply->setProperty( "requestData", QVariant::fromValue< Tomahawk::InfoSystem::InfoRequestData >( requestData ) );
connect( reply, SIGNAL( finished() ), SLOT( coverArtReturned() ) );
connect( reply, SIGNAL( finished() ), SLOT( albumInfoReturned() ) );
return;
}
@@ -726,6 +719,40 @@ LastFmInfoPlugin::topTracksReturned()
}
void
LastFmInfoPlugin::albumInfoReturned()
{
QNetworkReply* reply = qobject_cast<QNetworkReply*>( sender() );
QHash< QString, QString > covers;
QString url;
lastfm::XmlQuery lfm;
lfm.parse( reply->readAll() );
foreach ( lastfm::XmlQuery xq, lfm.children( "album" ) )
{
foreach ( lastfm::XmlQuery xxq, xq.children( "image" ) )
{
covers[ xxq.attribute( "size" ).toLower() ] = xxq.text();
}
}
if ( covers.contains( "mega" ) )
url = covers[ "mega" ];
else if ( covers.contains( "extralarge" ) )
url = covers[ "extralarge" ];
else if ( covers.contains( "large" ) )
url = covers[ "large" ];
else if ( covers.contains( "medium" ) )
url = covers[ "medium" ];
QNetworkRequest req( url );
QNetworkReply* newReply = TomahawkUtils::nam()->get( req );
newReply->setProperty( "requestData", reply->property( "requestData" ) );
connect( newReply, SIGNAL( finished() ), SLOT( coverArtReturned() ) );
}
void
LastFmInfoPlugin::coverArtReturned()
{

View File

@@ -61,6 +61,7 @@ public slots:
void topTracksReturned();
void chartReturned();
void similarTracksReturned();
void albumInfoReturned();
protected slots:
virtual void init();

View File

@@ -53,9 +53,11 @@ PlayableItem::PlayableItem( const Tomahawk::album_ptr& album, PlayableItem* pare
: QObject( parent )
, m_album( album )
{
Q_ASSERT( !m_album.isNull() );
init( parent, row );
connect( album.data(), SIGNAL( updated() ), SIGNAL( dataChanged() ) );
connect( album.data(), SIGNAL( coverChanged() ), SIGNAL( coverChanged() ) );
}
@@ -63,9 +65,11 @@ PlayableItem::PlayableItem( const Tomahawk::artist_ptr& artist, PlayableItem* pa
: QObject( parent )
, m_artist( artist )
{
Q_ASSERT( !m_artist.isNull() );
init( parent, row );
connect( artist.data(), SIGNAL( updated() ), SIGNAL( dataChanged() ) );
connect( artist.data(), SIGNAL( coverChanged() ), SIGNAL( coverChanged() ) );
}
@@ -73,6 +77,7 @@ PlayableItem::PlayableItem( const Tomahawk::result_ptr& result, PlayableItem* pa
: QObject( parent )
, m_result( result )
{
Q_ASSERT( !m_result.isNull() );
init( parent, row );
}
@@ -81,6 +86,7 @@ PlayableItem::PlayableItem( const Tomahawk::query_ptr& query, PlayableItem* pare
: QObject( parent )
, m_query( query )
{
Q_ASSERT( !m_query.isNull() );
init( parent, row );
connect( query.data(), SIGNAL( socialActionsLoaded() ),
@@ -91,6 +97,9 @@ PlayableItem::PlayableItem( const Tomahawk::query_ptr& query, PlayableItem* pare
connect( query.data(), SIGNAL( resultsChanged() ),
SLOT( onResultsChanged() ) );
connect( query->displayQuery().data(), SIGNAL( coverChanged() ), SIGNAL( coverChanged() ) );
connect( query->displayQuery().data(), SIGNAL( coverChanged() ), SIGNAL( dataChanged() ) );
}
@@ -99,6 +108,7 @@ PlayableItem::PlayableItem( const Tomahawk::plentry_ptr& entry, PlayableItem* pa
, m_entry( entry )
{
m_query = entry->query();
Q_ASSERT( !m_query.isNull() );
init( parent, row );
connect( m_query.data(), SIGNAL( socialActionsLoaded() ),
@@ -109,6 +119,9 @@ PlayableItem::PlayableItem( const Tomahawk::plentry_ptr& entry, PlayableItem* pa
connect( m_query.data(), SIGNAL( resultsChanged() ),
SLOT( onResultsChanged() ) );
connect( m_query->displayQuery().data(), SIGNAL( coverChanged() ), SIGNAL( coverChanged() ) );
connect( m_query->displayQuery().data(), SIGNAL( coverChanged() ), SIGNAL( dataChanged() ) );
}
@@ -145,7 +158,16 @@ void
PlayableItem::onResultsChanged()
{
if ( !m_query->results().isEmpty() )
{
m_result = m_query->results().first();
if ( m_query->displayQuery()->coverLoaded() )
{
emit coverChanged();
}
connect( m_query->displayQuery().data(), SIGNAL( coverChanged() ), SIGNAL( dataChanged() ) );
connect( m_query->displayQuery().data(), SIGNAL( coverChanged() ), SIGNAL( coverChanged() ) );
}
else
m_result = result_ptr();

View File

@@ -30,7 +30,9 @@
class DLLEXPORT PlayableItem : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ name NOTIFY dataChanged)
Q_PROPERTY(QString artistName READ artistName NOTIFY dataChanged)
Q_PROPERTY(QString albumName READ albumName NOTIFY dataChanged)
public:
~PlayableItem();
@@ -65,6 +67,7 @@ public:
signals:
void dataChanged();
void coverChanged();
private slots:
void onResultsChanged();

View File

@@ -43,6 +43,12 @@ PlayableModel::PlayableModel( QObject* parent, bool loading )
, m_readOnly( true )
, m_loading( loading )
{
QHash<int, QByteArray> roleNames;
roleNames.insert( ArtistRole, "artistName" );
roleNames.insert( TrackRole, "trackName" );
roleNames.insert( CoverIDRole, "coverID" );
setRoleNames( roleNames );
connect( AudioEngine::instance(), SIGNAL( started( Tomahawk::result_ptr ) ), SLOT( onPlaybackStarted( Tomahawk::result_ptr ) ), Qt::DirectConnection );
connect( AudioEngine::instance(), SIGNAL( stopped() ), SLOT( onPlaybackStopped() ), Qt::DirectConnection );
@@ -160,6 +166,12 @@ PlayableModel::queryData( const query_ptr& query, int column, int role ) const
if ( role == Qt::SizeHintRole )
return QSize( 0, 18 );
if ( role == CoverIDRole )
{
query->cover( QSize( 0, 0 ) );
return query->coverId();
}
if ( role != Qt::DisplayRole ) // && role != Qt::ToolTipRole )
return QVariant();
@@ -192,7 +204,7 @@ PlayableModel::queryData( const query_ptr& query, int column, int role ) const
if ( query->albumpos() != 0 )
{
tPos = QString::number( query->albumpos() );
if( query->discnumber() == 0 )
if ( query->discnumber() == 0 )
return tPos;
else
return QString( "%1.%2" ).arg( QString::number( query->discnumber() ) )
@@ -254,15 +266,22 @@ PlayableModel::data( const QModelIndex& index, int role ) const
{
return QVariant();
}
if ( role == Qt::TextAlignmentRole )
else if ( role == Qt::TextAlignmentRole )
{
return QVariant( columnAlignment( index.column() ) );
}
int column = index.column();
if ( role < CoverIDRole && role >= Qt::UserRole )
{
// Map user-role to column
column = role - Qt::UserRole;
role = Qt::DisplayRole;
}
if ( !entry->query().isNull() )
{
return queryData( entry->query()->displayQuery(), index.column(), role );
return queryData( entry->query()->displayQuery(), column, role );
}
else if ( !entry->artist().isNull() )
{
@@ -320,6 +339,7 @@ PlayableModel::setCurrentItem( const QModelIndex& index )
m_currentIndex = QModelIndex();
m_currentUuid = QString();
}
emit currentItemChanged( m_currentIndex );
}
@@ -719,6 +739,18 @@ PlayableModel::itemFromIndex( const QModelIndex& index ) const
}
}
PlayableItem *PlayableModel::itemFromIndex(int itemIndex) const
{
QModelIndex modelIndex = index( itemIndex, 0, QModelIndex() );
if ( modelIndex.isValid() )
{
return static_cast<PlayableItem*>( modelIndex.internalPointer() );
}
else
{
return m_rootItem;
}
}
void
PlayableModel::appendArtist( const Tomahawk::artist_ptr& artist )

View File

@@ -38,7 +38,8 @@ class DLLEXPORT PlayableModel : public QAbstractItemModel
Q_OBJECT
public:
enum Columns {
enum Columns
{
Artist = 0,
Track = 1,
Composer = 2,
@@ -54,6 +55,25 @@ public:
Name = 12
};
enum PlayableRoles
{
ArtistRole = Qt::UserRole,
TrackRole,
ComposerRole,
AlbumRole,
AlbumPosRole,
DurationRole,
BitrateRole,
AgeRole,
YearRole,
FilesizeRole,
OriginRole,
ScoreRole,
NameRole,
CoverIDRole
};
explicit PlayableModel( QObject* parent = 0, bool loading = true );
virtual ~PlayableModel();
@@ -99,6 +119,8 @@ public:
virtual void ensureResolved();
PlayableItem* itemFromIndex( const QModelIndex& index ) const;
Q_INVOKABLE PlayableItem* itemFromIndex( int itemIndex ) const;
/// Returns a flat list of all tracks in this model
QList< Tomahawk::query_ptr > queries() const;
@@ -115,6 +137,8 @@ signals:
void loadingStarted();
void loadingFinished();
void currentItemChanged( const QPersistentModelIndex &currentIndex );
public slots:
virtual void setCurrentItem( const QModelIndex& index );

View File

@@ -583,3 +583,11 @@ PlayableProxyModel::setFilter( const QString& pattern )
emit filterChanged( pattern );
}
}
PlayableItem*
PlayableProxyModel::itemFromIndex(int itemIndex) const
{
// qDebug() << "returning item" << sourceModel()->itemFromIndex( itemIndex )->name();
QModelIndex modelIndex = index( itemIndex, 0 );
return sourceModel()->itemFromIndex( mapToSource( modelIndex ) );
}

View File

@@ -36,7 +36,7 @@ public:
{ Detailed = 0, Short = 1, ShortWithAvatars = 2, Large = 3, Collection = 4 };
enum PlayableProxyModelRole
{ StyleRole = Qt::UserRole + 1 };
{ StyleRole = Qt::UserRole + 100 };
explicit PlayableProxyModel ( QObject* parent = 0 );
virtual ~PlayableProxyModel() {}
@@ -67,6 +67,7 @@ public:
virtual void setMaxVisibleItems( int items );
virtual PlayableItem* itemFromIndex( const QModelIndex& index ) const { return sourceModel()->itemFromIndex( index ); }
Q_INVOKABLE virtual PlayableItem* itemFromIndex( int itemIndex ) const;
virtual Tomahawk::playlistinterface_ptr playlistInterface();

View File

@@ -56,6 +56,7 @@ void
Tomahawk::GeneratorInterface::addControl( const Tomahawk::dyncontrol_ptr& control )
{
m_controls << control;
emit controlAdded( control );
}
@@ -77,6 +78,7 @@ void
Tomahawk::GeneratorInterface::removeControl( const Tomahawk::dyncontrol_ptr& control )
{
m_controls.removeAll( control );
controlRemoved( control );
}

View File

@@ -59,7 +59,7 @@ public:
// empty QString means use default
/// The generator will keep track of all the controls it creates. No need to tell it about controls
/// you ask it to create
virtual dyncontrol_ptr createControl( const QString& type = QString() );
Q_INVOKABLE virtual dyncontrol_ptr createControl( const QString& type = QString() );
/// A logo to display for this generator, if it has one
virtual QPixmap logo();
@@ -127,6 +127,8 @@ signals:
void error( const QString& title, const QString& body);
void generated( const QList< Tomahawk::query_ptr>& queries );
void nextTrackGenerated( const Tomahawk::query_ptr& track );
void controlAdded(const dyncontrol_ptr& control);
void controlRemoved(const dyncontrol_ptr& control);
protected:
QString m_type;

View File

@@ -156,6 +156,7 @@ dyncontrol_ptr
EchonestGenerator::createControl( const QString& type )
{
m_controls << dyncontrol_ptr( new EchonestControl( type, GeneratorFactory::typeSelectors( m_type ) ) );
emit controlAdded( m_controls.last() );
return m_controls.last();
}
@@ -336,6 +337,8 @@ EchonestGenerator::getParams() throw( std::runtime_error )
} else {
emit paramsGenerated( params );
}
qDebug() << "ParamsGenerated" << params;
}

View File

@@ -71,7 +71,7 @@ public:
explicit EchonestGenerator( QObject* parent = 0 );
virtual ~EchonestGenerator();
virtual dyncontrol_ptr createControl( const QString& type = QString() );
Q_INVOKABLE virtual dyncontrol_ptr createControl( const QString& type = QString() );
virtual QPixmap logo();
virtual void generate ( int number = -1 );
virtual void startOnDemand();
@@ -80,7 +80,7 @@ public:
virtual bool onDemandSteerable() const { return false; }
virtual QWidget* steeringWidget() { return 0; }
static QStringList styles();
Q_INVOKABLE static QStringList styles();
static QStringList moods();
static QStringList userCatalogs();
static QByteArray catalogId( const QString& collectionId );

View File

@@ -0,0 +1,129 @@
#include "EchonestStation.h"
#include "dynamic/DynamicPlaylist.h"
#include "PlayableItem.h"
#include "audio/AudioEngine.h"
#include <echonest/Playlist.h>
namespace Tomahawk
{
EchonestStation::EchonestStation( PlayableProxyModel *model, dynplaylist_ptr playlist, QObject *parent )
: QObject( parent )
, m_name( model->sourceModel()->title() )
, m_model( model )
, m_playlist( playlist )
{
connect(m_playlist->generator().data(), SIGNAL(controlAdded(const dyncontrol_ptr&)), SLOT(controlsChanged()));
}
QString EchonestStation::name() const
{
return m_playlist->title();
}
void EchonestStation::setName(const QString &name)
{
m_playlist->setTitle( name );
emit nameChanged();
}
Tomahawk::DynamicControl* EchonestStation::mainControl() {
foreach(dyncontrol_ptr control, m_playlist->generator()->controls()) {
qDebug() << "got control" << control->selectedType();
if(control->selectedType() == "Artist" || control->selectedType() == "Style") {
return control.data();
}
}
return 0;
}
bool EchonestStation::configured()
{
return mainControl() != 0;
}
int EchonestStation::minTempo() const
{
dyncontrol_ptr minTempoControl = findControl( "Tempo", "min_tempo" );
return minTempoControl.isNull() ? 0 : minTempoControl->input().toInt();
}
int EchonestStation::maxTempo() const
{
dyncontrol_ptr maxTempoControl = findControl( "Tempo", "max_tempo" );
return maxTempoControl.isNull() ? 500 : maxTempoControl->input().toInt();
}
void EchonestStation::playItem(int row)
{
QModelIndex index( m_model->index( row, 0) );
if( index.isValid() ) {
PlayableItem* item = m_model->itemFromIndex( index );
if ( item && !item->query().isNull() )
{
m_model->setCurrentIndex( index );
AudioEngine::instance()->playItem( m_model->playlistInterface(), item->query() );
}
}
}
void EchonestStation::setMainControl( StationType type, const QString &value )
{
dyncontrol_ptr control = m_playlist->generator()->createControl( "echonest" );
if ( type == StationTypeStyle ) {
control->setSelectedType( "Style" );
} else if ( type == StationTypeArtist ) {
control->setSelectedType( "Artist" );
}
control->setMatch( "1" );
control->setInput( value );
qDebug() << "created control" << control->type() << control->selectedType() << control->match();
m_playlist->generator()->generate( 20 );
emit configurationChanged();
}
void EchonestStation::setTempo(int min, int max)
{
dyncontrol_ptr tempoMinControl = findControl("Tempo", "min_tempo");
dyncontrol_ptr tempoMaxControl = findControl("Tempo", "max_tempo");
if ( tempoMinControl.isNull() ) {
tempoMinControl = m_playlist->generator()->createControl( "echonest" );
tempoMinControl->setSelectedType( "Tempo" );
tempoMinControl->setMatch( "min_tempo" );
}
if ( tempoMaxControl.isNull() ) {
tempoMaxControl = m_playlist->generator()->createControl( "echonest" );
tempoMaxControl->setSelectedType( "Tempo" );
tempoMaxControl->setMatch( "max_tempo" );
}
tempoMinControl->setInput( QString::number( min ) );
tempoMaxControl->setInput( QString::number( max ) );
m_playlist->generator()->generate(20);
emit configurationChanged();
}
dyncontrol_ptr EchonestStation::findControl(const QString &selectedType, const QString &match) const
{
foreach ( dyncontrol_ptr control, m_playlist->generator()->controls() ) {
if ( control->selectedType() == selectedType && control->match() == match ) {
return control;
}
}
return dyncontrol_ptr();
}
void EchonestStation::controlsChanged()
{
Q_ASSERT(false);
}
}

View File

@@ -0,0 +1,59 @@
#ifndef ECHONESTSTATION_H
#define ECHONESTSTATION_H
#include "PlayableProxyModel.h"
#include "dynamic/GeneratorInterface.h"
namespace Tomahawk
{
class EchonestStation: public QObject
{
Q_OBJECT
Q_ENUMS(StationType)
Q_PROPERTY( QString name READ name WRITE setName NOTIFY nameChanged )
Q_PROPERTY( bool configured READ configured NOTIFY configurationChanged )
Q_PROPERTY( Tomahawk::DynamicControl* mainControl READ mainControl )
Q_PROPERTY( int minTempo READ minTempo NOTIFY configurationChanged )
Q_PROPERTY( int maxTempo READ maxTempo NOTIFY configurationChanged )
public:
enum StationType {
StationTypeStyle,
StationTypeArtist
};
EchonestStation( PlayableProxyModel *model, dynplaylist_ptr playlist, QObject *parent = 0);
QString name() const;
void setName( const QString &name );
Tomahawk::DynamicControl* mainControl();
bool configured();
int minTempo() const;
int maxTempo() const;
public slots:
void playItem( int row );
void setMainControl(StationType type, const QString &value);
void setTempo( int min, int max );
signals:
void nameChanged();
void configurationChanged();
private:
dyncontrol_ptr findControl( const QString &selectedType, const QString &match ) const;
private slots:
void controlsChanged();
private:
QString m_name;
PlayableProxyModel *m_model;
dynplaylist_ptr m_playlist;
};
}
#endif

View File

@@ -0,0 +1,205 @@
#include "DynamicQmlWidget.h"
#include "dynamic/echonest/EchonestStation.h"
#include "playlist/dynamic/DynamicModel.h"
#include "playlist/PlayableProxyModel.h"
#include "utils/TomahawkUtilsGui.h"
#include "dynamic/DynamicModel.h"
#include "dynamic/echonest/EchonestControl.h"
#include "dynamic/GeneratorInterface.h"
#include "PlayableItem.h"
#include "Source.h"
#include "widgets/DeclarativeCoverArtProvider.h"
#include "audio/AudioEngine.h"
#include <QUrl>
#include <qdeclarative.h>
#include <QDeclarativeContext>
#include <QDeclarativeEngine>
#include <QSize>
namespace Tomahawk
{
DynamicQmlWidget::DynamicQmlWidget( const dynplaylist_ptr& playlist, QWidget* parent )
: QDeclarativeView( parent )
, m_playlist( playlist )
, m_runningOnDemand( false )
, m_activePlaylist( false )
{
setResizeMode( QDeclarativeView::SizeRootObjectToView );
m_model = new DynamicModel( this );
m_proxyModel = new PlayableProxyModel( this );
m_proxyModel->setSourcePlayableModel( m_model );
m_proxyModel->setShowOfflineResults( false );
// QML image providers will be deleted by the view
engine()->addImageProvider( "albumart", new DeclarativeCoverArtProvider( m_proxyModel ) );
m_model->loadPlaylist( m_playlist );
// Initially seed the playlist
m_playlist->generator()->generate( 20 );
qDebug() << "###got" << m_playlist->generator()->controls().size() << "controls";
qmlRegisterUncreatableType<EchonestStation>("tomahawk", 1, 0, "EchonestStation", "bla");
// TODO: In case QML is used in more places, this should probably be moved to some generic place
qmlRegisterType<PlayableItem>("tomahawk", 1, 0, "PlayableItem");
qmlRegisterUncreatableType<GeneratorInterface>("tomahawk", 1, 0, "Generator", "you cannot create it on your own - should be set in context");
qmlRegisterUncreatableType<PlayableItem>("tomahawk", 1, 0, "PlayableItem", "you cannot create it on your own - they will appear in the model");
EchonestStation *station = new EchonestStation( m_proxyModel, m_playlist, this);
rootContext()->setContextProperty( "echonestStation", station);
rootContext()->setContextProperty( "dynamicModel", m_proxyModel );
rootContext()->setContextProperty( "generator", m_playlist->generator().data() );
setSource( QUrl( "qrc" RESPATH "qml/StationScene.qml" ) );
connect( m_model, SIGNAL( currentItemChanged( QPersistentModelIndex ) ), SLOT( currentItemChanged( QPersistentModelIndex ) ) );
connect( m_playlist->generator().data(), SIGNAL( generated( QList<Tomahawk::query_ptr> ) ), this, SLOT( tracksGenerated( QList<Tomahawk::query_ptr> ) ) );
connect( m_playlist->generator().data(), SIGNAL( nextTrackGenerated( Tomahawk::query_ptr ) ), this, SLOT( nextTrackGenerated( Tomahawk::query_ptr ) ) );
connect( m_playlist.data(), SIGNAL( dynamicRevisionLoaded( Tomahawk::DynamicPlaylistRevision ) ), this, SLOT( onRevisionLoaded( Tomahawk::DynamicPlaylistRevision ) ) );
connect( m_playlist->generator().data(), SIGNAL( error( QString, QString )), SLOT( error(QString,QString) ) );
connect( AudioEngine::instance(), SIGNAL( started( Tomahawk::result_ptr ) ), this, SLOT( trackStarted() ) );
connect( AudioEngine::instance(), SIGNAL( playlistChanged( Tomahawk::playlistinterface_ptr ) ), this, SLOT( playlistChanged( Tomahawk::playlistinterface_ptr ) ) );
}
DynamicQmlWidget::~DynamicQmlWidget()
{
}
Tomahawk::playlistinterface_ptr
DynamicQmlWidget::playlistInterface() const
{
return m_proxyModel->playlistInterface();
}
QString
DynamicQmlWidget::title() const
{
return m_model->title();
}
QString
DynamicQmlWidget::description() const
{
return m_model->description();
}
QPixmap
DynamicQmlWidget::pixmap() const
{
return QPixmap( RESPATH "images/station.png" );
}
bool
DynamicQmlWidget::jumpToCurrentTrack()
{
return true;
}
void DynamicQmlWidget::currentItemChanged( const QPersistentModelIndex &currentIndex )
{
rootContext()->setContextProperty( "currentlyPlayedIndex", m_proxyModel->mapFromSource( currentIndex ).row() );
}
void
DynamicQmlWidget::tracksGenerated( const QList< query_ptr >& queries )
{
qDebug() << queries.count() << "tracks generated";
m_model->tracksGenerated( queries, queries.count() );
m_playlist->resolve();
}
void DynamicQmlWidget::nextTrackGenerated(const query_ptr &track)
{
m_model->tracksGenerated( QList<query_ptr>() << track );
m_playlist->resolve();
connect( track.data(), SIGNAL( resolvingFinished( bool )), SLOT( resolvingFinished( bool ) ) );
}
void DynamicQmlWidget::error(const QString &title, const QString &body)
{
qDebug() << "got a generator error:" << title << body;
// m_playlist->generator()->fetchNext();
}
void DynamicQmlWidget::onRevisionLoaded(DynamicPlaylistRevision)
{
m_playlist->resolve();
}
void DynamicQmlWidget::resolvingFinished(bool hasResults)
{
Q_UNUSED(hasResults)
qDebug() << "next track generated" << m_proxyModel->rowCount() << m_proxyModel->currentIndex().row();
if( m_proxyModel->rowCount() <= m_proxyModel->currentIndex().row() + 8 ) {
qDebug() << "fetching next one";
m_playlist->generator()->fetchNext();
}
}
void DynamicQmlWidget::trackStarted()
{
if ( m_activePlaylist && !m_playlist.isNull() &&
m_playlist->mode() == OnDemand && !m_runningOnDemand )
{
startStation();
}
}
void
DynamicQmlWidget::playlistChanged( Tomahawk::playlistinterface_ptr pl )
{
if ( pl == m_proxyModel->playlistInterface() ) // same playlist
m_activePlaylist = true;
else
{
m_activePlaylist = false;
// user started playing something somewhere else, so give it a rest
if ( m_runningOnDemand )
{
stopStation( false );
}
}
}
void
DynamicQmlWidget::stopStation( bool stopPlaying )
{
m_model->stopOnDemand( stopPlaying );
m_runningOnDemand = false;
}
void
DynamicQmlWidget::startStation()
{
m_runningOnDemand = true;
m_model->startOnDemand();
}
}

View File

@@ -0,0 +1,111 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
* Copyright 2012, Michael Zanetti <mzanetti@kde.org>
*
* Tomahawk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Tomahawk is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DYNAMIC_QML_WIDGET_H
#define DYNAMIC_QML_WIDGET_H
#include "ViewPage.h"
#include "Typedefs.h"
#include <QDeclarativeView>
#include <QDeclarativeImageProvider>
class PlayableProxyModel;
namespace Tomahawk
{
class DynamicModel;
class DynamicQmlWidget : public QDeclarativeView, public Tomahawk::ViewPage
{
Q_OBJECT
public:
explicit DynamicQmlWidget( const dynplaylist_ptr& playlist, QWidget* parent = 0 );
virtual ~DynamicQmlWidget();
virtual QWidget* widget() { return this; }
virtual Tomahawk::playlistinterface_ptr playlistInterface() const;
virtual QString title() const;
virtual QString description() const;
virtual QPixmap pixmap() const;
virtual bool showInfoBar() const { return false; }
virtual bool showModes() const { return false; }
virtual bool showFilter() const { return false; }
virtual bool jumpToCurrentTrack();
private slots:
void currentItemChanged( const QPersistentModelIndex &currentIndex );
void tracksGenerated( const QList< Tomahawk::query_ptr>& queries );
void nextTrackGenerated( const Tomahawk::query_ptr& track );
void error( const QString& title, const QString& body);
void onRevisionLoaded( Tomahawk::DynamicPlaylistRevision );
void playlistChanged( Tomahawk::playlistinterface_ptr pl );
void resolvingFinished( bool hasResults );
void trackStarted();
void startStation();
void stopStation( bool stopPlaying );
private:
DynamicModel* m_model;
PlayableProxyModel* m_proxyModel;
dynplaylist_ptr m_playlist;
bool m_runningOnDemand;
bool m_activePlaylist;
};
}
#include "dynamic/GeneratorInterface.h"
namespace Tomahawk
{
class ControlModel: public QAbstractListModel
{
Q_OBJECT
public:
ControlModel(geninterface_ptr generator, QObject *parent = 0): QAbstractListModel(parent), m_generator(generator) {
connect(generator.data(), SIGNAL(controlAdded(const dyncontrol_ptr&)), SLOT(controlAdded()));
}
int rowCount(const QModelIndex &parent) const { return m_generator->controls().size(); }
QVariant data(const QModelIndex &index, int role) const {
return "blabla";
}
Q_INVOKABLE Tomahawk::DynamicControl *controlAt( int index ) { qDebug() << "returning" << m_generator->controls().at(index).data(); return m_generator->controls().at(index).data(); }
private slots:
void controlAdded() {
qDebug() << "control added";
beginInsertRows(QModelIndex(), m_generator->controls().size() - 1, m_generator->controls().size() - 1);
endInsertRows();
}
private:
geninterface_ptr m_generator;
};
}
#endif // DYNAMIC_QML_WIDGET_H

View File

@@ -0,0 +1,69 @@
#include "DeclarativeCoverArtProvider.h"
#include "PlayableItem.h"
#include "playlist/PlayableProxyModel.h"
#include "Query.h"
#include "Album.h"
#include "Artist.h"
#include <QDeclarativeImageProvider>
#include <QModelIndex>
#include <QDebug>
namespace Tomahawk
{
DeclarativeCoverArtProvider::DeclarativeCoverArtProvider( PlayableProxyModel *model )
: QDeclarativeImageProvider( QDeclarativeImageProvider::Pixmap )
, m_model( model )
{
}
DeclarativeCoverArtProvider::~DeclarativeCoverArtProvider()
{
}
QPixmap DeclarativeCoverArtProvider::requestPixmap(const QString &id, QSize *size, const QSize &requestedSize)
{
// We always can generate it in the requested size
int width = requestedSize.width() > 0 ? requestedSize.width() : 230;
int height = requestedSize.height() > 0 ? requestedSize.height() : 230;
if( size )
*size = QSize( width, height );
// PlayableItem *item = m_model->itemFromIndex( id.toInt() );
// if( item ) {
// qDebug() << "item:" << item;
// qDebug() << "item2:" << item->artistName() << item->name();
// if ( !item->query().isNull() ) {
// return item->query()->displayQuery()->cover( *size );
// }
// }
tDebug() << "Getting by id:" << id;
album_ptr album = Album::getByCoverId( id );
if ( !album.isNull() )
{
tDebug() << "Returning album cover:" << album->cover( requestedSize ).isNull();
return album->cover( requestedSize );
}
artist_ptr artist = Artist::getByCoverId( id );
if ( !artist.isNull() )
{
tDebug() << "Returning artist cover:" << artist->cover( requestedSize ).isNull();
return artist->cover( requestedSize );
}
/* query_ptr query = Query::getByCoverId( id );
if ( !query.isNull() ) {
return query->cover( requestedSize );
}*/
// TODO: create default cover art image
QPixmap pixmap( *size );
pixmap.fill();
return pixmap;
}
}

View File

@@ -0,0 +1,26 @@
#ifndef DECLARATIVECOVERARTPROVIDER_H
#define DECLARATIVECOVERARTPROVIDER_H
#include "playlist/PlayableProxyModel.h"
#include <QDeclarativeImageProvider>
namespace Tomahawk
{
class DeclarativeCoverArtProvider: public QDeclarativeImageProvider
{
public:
DeclarativeCoverArtProvider( PlayableProxyModel *model );
~DeclarativeCoverArtProvider();
QPixmap requestPixmap( const QString &id, QSize *size, const QSize &requestedSize );
private:
PlayableProxyModel *m_model;
};
}
#endif // DECLARATIVECOVERARTPROVIDER_H

View File

@@ -0,0 +1,18 @@
#include "AlbumArtImageProvider.h"
#include <QDebug>
QPixmap AlbumArtImageProvider::requestPixmap(const QString &id, QSize *size, const QSize &requestedSize)
{
qDebug() << "*!*!*!*!*!*!*!*!*!* image requested";
int width = 100;
int height = 50;
if (size)
*size = QSize(width, height);
QPixmap pixmap(requestedSize.width() > 0 ? requestedSize.width() : width,
requestedSize.height() > 0 ? requestedSize.height() : height);
pixmap.fill(QColor(id).rgba());
return pixmap;
}

View File

@@ -0,0 +1,12 @@
#include <QDeclarativeImageProvider>
class AlbumArtImageProvider : public QDeclarativeImageProvider
{
public:
AlbumArtImageProvider()
: QDeclarativeImageProvider(QDeclarativeImageProvider::Pixmap)
{
}
QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize);
};

View File

@@ -23,6 +23,9 @@
#include <QScrollArea>
#include <QScrollBar>
#include <QDeclarativeContext>
#include <QDeclarativeEngine>
#include "AlbumArtImageProvider.h"
#include "audio/AudioEngine.h"
#include "playlist/GridItemDelegate.h"
@@ -44,7 +47,7 @@ using namespace Tomahawk;
ArtistInfoWidget::ArtistInfoWidget( const Tomahawk::artist_ptr& artist, QWidget* parent )
: QWidget( parent )
: QDeclarativeView( parent )
, ui( new Ui::ArtistInfoWidget )
, m_artist( artist )
{
@@ -159,7 +162,7 @@ ArtistInfoWidget::ArtistInfoWidget( const Tomahawk::artist_ptr& artist, QWidget*
ArtistInfoWidget::~ArtistInfoWidget()
{
delete ui;
// delete ui;
}
@@ -239,9 +242,9 @@ ArtistInfoWidget::load( const artist_ptr& artist )
connect( m_artist.data(), SIGNAL( tracksAdded( QList<Tomahawk::query_ptr>, Tomahawk::ModelMode, Tomahawk::collection_ptr ) ),
SLOT( onTracksFound( QList<Tomahawk::query_ptr>, Tomahawk::ModelMode ) ) );
ui->artistLabel->setText( artist->name() );
// ui->artistLabel->setText( artist->name() );
m_topHitsModel->startLoading();
// m_topHitsModel->startLoading();
if ( !m_artist->albums( Mixed ).isEmpty() )
onAlbumsFound( m_artist->albums( Mixed ), Mixed );
@@ -273,38 +276,38 @@ ArtistInfoWidget::onTracksFound( const QList<Tomahawk::query_ptr>& queries, Mode
{
Q_UNUSED( mode );
m_topHitsModel->finishLoading();
m_topHitsModel->appendQueries( queries );
// m_topHitsModel->finishLoading();
// m_topHitsModel->appendQueries( queries );
}
void
ArtistInfoWidget::onSimilarArtistsLoaded()
{
m_relatedModel->appendArtists( m_artist->similarArtists() );
// m_relatedModel->appendArtists( m_artist->similarArtists() );
}
void
ArtistInfoWidget::onBiographyLoaded()
{
m_longDescription = m_artist->biography();
emit longDescriptionChanged( m_longDescription );
// m_longDescription = m_artist->biography();
// emit longDescriptionChanged( m_longDescription );
ui->biography->setHtml( m_artist->biography() );
// ui->biography->setHtml( m_artist->biography() );
}
void
ArtistInfoWidget::onArtistImageUpdated()
{
if ( m_artist->cover( QSize( 0, 0 ) ).isNull() )
return;
// if ( m_artist->cover( QSize( 0, 0 ) ).isNull() )
// return;
m_pixmap = m_artist->cover( QSize( 0, 0 ) );
emit pixmapChanged( m_pixmap );
// m_pixmap = m_artist->cover( QSize( 0, 0 ) );
// emit pixmapChanged( m_pixmap );
ui->cover->setPixmap( m_artist->cover( ui->cover->sizeHint() ) );
// ui->cover->setPixmap( m_artist->cover( ui->cover->sizeHint() ) );
}
@@ -315,7 +318,7 @@ ArtistInfoWidget::changeEvent( QEvent* e )
switch ( e->type() )
{
case QEvent::LanguageChange:
ui->retranslateUi( this );
// ui->retranslateUi( this );
break;
default:

View File

@@ -31,11 +31,13 @@
#define ARTISTINFOWIDGET_H
#include <QWidget>
#include <QDeclarativeView>
#include "Typedefs.h"
#include "PlaylistInterface.h"
#include "ViewPage.h"
#include "DllMacro.h"
class PlayableModel;
@@ -48,7 +50,7 @@ namespace Ui
class MetaArtistInfoInterface;
class DLLEXPORT ArtistInfoWidget : public QWidget, public Tomahawk::ViewPage
class DLLEXPORT ArtistInfoWidget : public QDeclarativeView, public Tomahawk::ViewPage
{
Q_OBJECT