mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-09-06 04:02:54 +02:00
Compare commits
88 Commits
hugolm84-t
...
0.2.3
Author | SHA1 | Date | |
---|---|---|---|
|
f7e82368bd | ||
|
b54670ad48 | ||
|
1a869762f6 | ||
|
8af49897a9 | ||
|
6571a0b88e | ||
|
70b350510f | ||
|
72471f70d3 | ||
|
6fe16be23b | ||
|
a3833c1da5 | ||
|
053652756a | ||
|
33ee2a4724 | ||
|
c15c1531f8 | ||
|
e3d1f2ea8c | ||
|
ecc9502c2c | ||
|
446dd993a8 | ||
|
2e19306458 | ||
|
b256141f74 | ||
|
61ddd9bfa1 | ||
|
bce77397a7 | ||
|
47f0895efb | ||
|
a16139266b | ||
|
e050b99550 | ||
|
92b2fdcb2e | ||
|
ab72133c15 | ||
|
44a9c35413 | ||
|
e7e2a7775d | ||
|
f0d677ce52 | ||
|
4687e73aa9 | ||
|
fcb70b551b | ||
|
5975d45ca4 | ||
|
95b99f4e8c | ||
|
4047588086 | ||
|
cdd1c05f22 | ||
|
c4b595d446 | ||
|
0732ce120a | ||
|
e62a868562 | ||
|
67c9e79dac | ||
|
037f7a4f57 | ||
|
bedf36c3f6 | ||
|
fcc4cbbc55 | ||
|
5e95567db0 | ||
|
f9591e800c | ||
|
c887bbdd57 | ||
|
0a0c8607fc | ||
|
756ff7c869 | ||
|
5374d65a05 | ||
|
4327d61df7 | ||
|
5a9fb8d1cc | ||
|
a169972723 | ||
|
1279b1fa12 | ||
|
fd99fa84be | ||
|
13ab10adea | ||
|
20d2a5ff59 | ||
|
6b9eec00fd | ||
|
d7416ddd57 | ||
|
2e9aa7f3b3 | ||
|
208393deb0 | ||
|
b923d4f994 | ||
|
edbee5a922 | ||
|
e0bdc4b8bc | ||
|
4b53d20663 | ||
|
74c4f4ddc2 | ||
|
ec03ece35c | ||
|
d217e7fae0 | ||
|
bc3bcc708f | ||
|
7a90ba11bb | ||
|
ed219a56cd | ||
|
1537d5b08a | ||
|
263340a270 | ||
|
bf54ebf7fe | ||
|
bfbac296b0 | ||
|
7971e7aadc | ||
|
4cc1690dea | ||
|
2090d76955 | ||
|
d09397a8ab | ||
|
a734cad4e1 | ||
|
9b433379ee | ||
|
2e11376d01 | ||
|
9ba11290ae | ||
|
97e0bbaf38 | ||
|
eb4242622d | ||
|
469bea43ba | ||
|
f9f3a45a31 | ||
|
0579d63013 | ||
|
1bb115ec6f | ||
|
5f320028b8 | ||
|
b0d445c262 | ||
|
479a0c469f |
@@ -16,7 +16,7 @@ SET( TOMAHAWK_DESCRIPTION_SUMMARY "The social media player" )
|
||||
|
||||
SET( TOMAHAWK_VERSION_MAJOR 0 )
|
||||
SET( TOMAHAWK_VERSION_MINOR 2 )
|
||||
SET( TOMAHAWK_VERSION_PATCH 1 )
|
||||
SET( TOMAHAWK_VERSION_PATCH 3 )
|
||||
|
||||
#SET( TOMAHAWK_VERSION_RC 0 )
|
||||
|
||||
@@ -72,6 +72,10 @@ ELSE()
|
||||
LIST(APPEND NEEDED_QT4_COMPONENTS "QtGui" "QtWebkit" )
|
||||
ENDIF()
|
||||
|
||||
IF( BUILD_GUI AND UNIX AND NOT APPLE )
|
||||
FIND_PACKAGE( X11 )
|
||||
ENDIF()
|
||||
|
||||
macro_optional_find_package(Qt4 4.7.0 COMPONENTS ${NEEDED_QT4_COMPONENTS} )
|
||||
macro_log_feature(QT4_FOUND "Qt" "A cross-platform application and UI framework" "http://qt.nokia.com" TRUE "" "If you see this, although libqt4-devel is installed, check whether \n the qtwebkit-devel package is installed as well")
|
||||
|
||||
|
@@ -203,7 +203,7 @@ Function PageReinstall
|
||||
IntCmp $R0 ${VER_MINOR} build_check new_version older_version
|
||||
build_check:
|
||||
ReadRegDWORD $R0 HKLM "Software\Tomahawk" "VersionBuild"
|
||||
IntCmp $R0 ${VER_BUILD} new_version older_version
|
||||
IntCmp $R0 ${VER_BUILD} same_version new_version older_version
|
||||
|
||||
new_version:
|
||||
!insertmacro INSTALLOPTIONS_WRITE "NSIS.InstallOptions.ini" "Field 1" "Text" "An older version of Tomahawk is installed on your system. It is recommended that you uninstall the current version before installing. Select the operation you want to perform and click Next to continue."
|
||||
|
23
ChangeLog
23
ChangeLog
@@ -1,3 +1,26 @@
|
||||
Version 0.2.3:
|
||||
* Fixed opening Rdio and Spotify links.
|
||||
* Fixed potential crash in sidebar during syncing of sources.
|
||||
* When Listening Along, the last song a peer plays is no longer duplicated.
|
||||
* Fixed an issue where the Twitter plugin could get out of sync if the
|
||||
database was cleared, leading to eventual crashes when re-connecting.
|
||||
* Fixed duplicate albums showing up on Dashboard.
|
||||
* Automatically sort search results by score.
|
||||
* Fixed stations being stuck not fetching more songs.
|
||||
* Fixed issue where artist bio could be referring to a different artist.
|
||||
* Opening a "tomahawk" URL (or other URL with Tomahawk) brings the Tomahawk
|
||||
window to the foreground.
|
||||
|
||||
Version 0.2.2:
|
||||
* Fixed crash pressing previous and next when playing a song from the Queue.
|
||||
* Fixed issue where wrench for newly added resolvers would not show up.
|
||||
* Fixed sidebar statistics not updating after collection scan finished.
|
||||
* Fixed omitting a few tracks in the Collection tree-view.
|
||||
* Fixed sidebar & track sorting issues.
|
||||
* Seek- & volume sliders now directly jump to the position you clicked on.
|
||||
* Added ability to drag artists and albums within Tomahawk.
|
||||
* (OS X) Fixed Ogg Vorbis support.
|
||||
|
||||
Version 0.2.1:
|
||||
* Fixed crashing trying to play an unavailable track.
|
||||
* Fixed a crash caused by using Javascript resolvers.
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 19 KiB |
@@ -237,7 +237,6 @@ TARGET_LINK_LIBRARIES( tomahawk
|
||||
${QXTWEB_LIBRARIES}
|
||||
${QJSON_LIBRARIES}
|
||||
${TAGLIB_LIBRARIES}
|
||||
${CLUCENE_LIBRARIES}
|
||||
)
|
||||
|
||||
|
||||
|
@@ -35,6 +35,7 @@
|
||||
#include "utils/tomahawkutils.h"
|
||||
#include "utils/logger.h"
|
||||
#include <globalactionmanager.h>
|
||||
#include "dropjob.h"
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
@@ -90,56 +91,9 @@ AudioControls::AudioControls( QWidget* parent )
|
||||
ui->ownerLabel->setForegroundRole( QPalette::Dark );
|
||||
ui->metaDataArea->setStyleSheet( "QWidget#metaDataArea {\nborder-width: 4px;\nborder-image: url(" RESPATH "images/now-playing-panel.png) 4 4 4 4 stretch stretch; }" );
|
||||
|
||||
ui->seekSlider->setFixedHeight( 20 );
|
||||
ui->seekSlider->setEnabled( true );
|
||||
ui->seekSlider->setStyleSheet( "QSlider::groove::horizontal {"
|
||||
"margin: 5px; border-width: 3px;"
|
||||
"border-image: url(" RESPATH "images/seek-slider-bkg.png) 3 3 3 3 stretch stretch;"
|
||||
"}"
|
||||
|
||||
"QSlider::sub-page:horizontal {"
|
||||
"margin: 5px; border-width: 3px;"
|
||||
"border-image: url(" RESPATH "images/seek-slider-level.png) 3 3 3 3 stretch stretch;"
|
||||
"}"
|
||||
|
||||
"QSlider::handle::horizontal {"
|
||||
"margin-bottom: -7px; margin-top: -7px;"
|
||||
"margin-left: -4px; margin-right: -4px;"
|
||||
"height: 17px; width: 16px;"
|
||||
"background-image: url(" RESPATH "images/seek-and-volume-knob-rest.png);"
|
||||
"background-repeat: no-repeat;"
|
||||
"}" );
|
||||
|
||||
ui->volumeSlider->setFixedHeight( 20 );
|
||||
ui->volumeSlider->setRange( 0, 100 );
|
||||
ui->volumeSlider->setValue( AudioEngine::instance()->volume() );
|
||||
ui->volumeSlider->setStyleSheet( "QSlider::groove::horizontal {"
|
||||
"margin: 5px; border-width: 3px;"
|
||||
"border-image: url(" RESPATH "images/volume-slider-bkg.png) 3 3 3 3 stretch stretch;"
|
||||
"}"
|
||||
|
||||
"QSlider::sub-page:horizontal {"
|
||||
"margin: 5px; border-width: 3px;"
|
||||
"border-image: url(" RESPATH "images/seek-slider-level.png) 3 3 3 3 stretch stretch;"
|
||||
"}"
|
||||
|
||||
"QSlider::handle::horizontal {"
|
||||
"margin-bottom: -7px; margin-top: -7px;"
|
||||
"margin-left: -4px; margin-right: -4px;"
|
||||
"height: 17px; width: 16px;"
|
||||
"background-image: url(" RESPATH "images/seek-and-volume-knob-rest.png);"
|
||||
"background-repeat: no-repeat;"
|
||||
"}" );
|
||||
|
||||
/* m_playAction = new QAction( this );
|
||||
m_pauseAction = new QAction( this );
|
||||
m_prevAction = new QAction( this );
|
||||
m_nextAction = new QAction( this );
|
||||
|
||||
connect( m_playAction, SIGNAL( triggered() ), (QObject*)APP->audioEngine(), SLOT( play() ) );
|
||||
connect( m_pauseAction, SIGNAL( triggered() ), (QObject*)APP->audioEngine(), SLOT( pause() ) );
|
||||
connect( m_prevAction, SIGNAL( triggered() ), (QObject*)APP->audioEngine(), SLOT( previous() ) );
|
||||
connect( m_nextAction, SIGNAL( triggered() ), (QObject*)APP->audioEngine(), SLOT( next() ) ); */
|
||||
|
||||
connect( ui->seekSlider, SIGNAL( valueChanged( int ) ), AudioEngine::instance(), SLOT( seek( int ) ) );
|
||||
connect( ui->volumeSlider, SIGNAL( valueChanged( int ) ), AudioEngine::instance(), SLOT( setVolume( int ) ) );
|
||||
@@ -179,7 +133,6 @@ AudioControls::AudioControls( QWidget* parent )
|
||||
|
||||
connect( Tomahawk::InfoSystem::InfoSystem::instance(), SIGNAL( finished( QString ) ), SLOT( infoSystemFinished( QString ) ) );
|
||||
|
||||
|
||||
ui->buttonAreaLayout->setSpacing( 0 );
|
||||
ui->stackedLayout->setSpacing( 0 );
|
||||
ui->stackedLayout->setContentsMargins( 0, 0, 0, 0 );
|
||||
@@ -305,9 +258,6 @@ AudioControls::onPlaybackLoading( const Tomahawk::result_ptr& result )
|
||||
ui->seekSlider->setValue( 0 );
|
||||
ui->seekSlider->setVisible( true );
|
||||
|
||||
/* m_playAction->setEnabled( false );
|
||||
m_pauseAction->setEnabled( true ); */
|
||||
|
||||
ui->stackedLayout->setCurrentWidget( ui->pauseButton );
|
||||
|
||||
ui->loveButton->setEnabled( true );
|
||||
@@ -343,18 +293,12 @@ AudioControls::socialActionsLoaded()
|
||||
void
|
||||
AudioControls::onPlaybackPaused()
|
||||
{
|
||||
/* m_pauseAction->setEnabled( false );
|
||||
m_playAction->setEnabled( true ); */
|
||||
|
||||
ui->stackedLayout->setCurrentWidget( ui->playPauseButton );
|
||||
}
|
||||
|
||||
void
|
||||
AudioControls::onPlaybackResumed()
|
||||
{
|
||||
/* m_playAction->setEnabled( false );
|
||||
m_pauseAction->setEnabled( true ); */
|
||||
|
||||
ui->stackedLayout->setCurrentWidget( ui->pauseButton );
|
||||
ui->loveButton->setVisible( true );
|
||||
}
|
||||
@@ -376,9 +320,6 @@ AudioControls::onPlaybackStopped()
|
||||
ui->stackedLayout->setCurrentWidget( ui->playPauseButton );
|
||||
ui->loveButton->setEnabled( false );
|
||||
ui->loveButton->setVisible( false );
|
||||
|
||||
/* m_pauseAction->setEnabled( false );
|
||||
m_playAction->setEnabled( true ); */
|
||||
}
|
||||
|
||||
|
||||
@@ -521,7 +462,7 @@ AudioControls::onTrackClicked()
|
||||
void
|
||||
AudioControls::dragEnterEvent( QDragEnterEvent* e )
|
||||
{
|
||||
if ( GlobalActionManager::instance()->acceptsMimeData( e->mimeData() ) )
|
||||
if ( DropJob::acceptsMimeData( e->mimeData() ) )
|
||||
e->acceptProposedAction();
|
||||
}
|
||||
|
||||
@@ -538,10 +479,11 @@ void
|
||||
AudioControls::dropEvent( QDropEvent* e )
|
||||
{
|
||||
tDebug() << "AudioControls got drop:" << e->mimeData()->formats();
|
||||
if ( GlobalActionManager::instance()->acceptsMimeData( e->mimeData() ) )
|
||||
if ( DropJob::acceptsMimeData( e->mimeData() ) )
|
||||
{
|
||||
connect( GlobalActionManager::instance(), SIGNAL( tracks( QList<Tomahawk::query_ptr> ) ), this, SLOT( droppedTracks( QList<Tomahawk::query_ptr> ) ) );
|
||||
GlobalActionManager::instance()->tracksFromMimeData( e->mimeData() );
|
||||
DropJob *dj = new DropJob();
|
||||
connect( dj, SIGNAL( tracks( QList<Tomahawk::query_ptr> ) ), this, SLOT( droppedTracks( QList<Tomahawk::query_ptr> ) ) );
|
||||
dj->tracksFromMimeData( e->mimeData() );
|
||||
|
||||
e->accept();
|
||||
}
|
||||
@@ -551,8 +493,6 @@ AudioControls::dropEvent( QDropEvent* e )
|
||||
void
|
||||
AudioControls::droppedTracks( QList< query_ptr > tracks )
|
||||
{
|
||||
disconnect( GlobalActionManager::instance(), SIGNAL( tracks( QList<Tomahawk::query_ptr> ) ), this, SLOT( droppedTracks( QList<Tomahawk::query_ptr> ) ) );
|
||||
|
||||
if ( !tracks.isEmpty() )
|
||||
{
|
||||
// queue and play the first if nothign is playing
|
||||
|
@@ -82,11 +82,6 @@ private slots:
|
||||
private:
|
||||
Ui::AudioControls *ui;
|
||||
|
||||
QAction* m_playAction;
|
||||
QAction* m_pauseAction;
|
||||
QAction* m_prevAction;
|
||||
QAction* m_nextAction;
|
||||
|
||||
QPixmap m_defaultCover;
|
||||
|
||||
Tomahawk::result_ptr m_currentTrack;
|
||||
|
@@ -337,7 +337,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="seekSlider">
|
||||
<widget class="SeekSlider" name="seekSlider">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
@@ -489,7 +489,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="volumeSlider">
|
||||
<widget class="SeekSlider" name="volumeSlider">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
@@ -529,6 +529,11 @@
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>SeekSlider</class>
|
||||
<extends>QSlider</extends>
|
||||
<header location="global">widgets/SeekSlider.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ImageButton</class>
|
||||
<extends>QPushButton</extends>
|
||||
|
@@ -31,6 +31,7 @@ set( libSources
|
||||
viewmanager.cpp
|
||||
globalactionmanager.cpp
|
||||
contextmenu.cpp
|
||||
dropjob.cpp
|
||||
|
||||
sip/SipPlugin.cpp
|
||||
sip/SipHandler.cpp
|
||||
@@ -176,6 +177,7 @@ set( libSources
|
||||
|
||||
widgets/newplaylistwidget.cpp
|
||||
widgets/searchwidget.cpp
|
||||
widgets/SeekSlider.cpp
|
||||
widgets/playlisttypeselectordlg.cpp
|
||||
widgets/welcomewidget.cpp
|
||||
widgets/welcomeplaylistmodel.cpp
|
||||
@@ -208,6 +210,7 @@ set( libHeaders
|
||||
viewmanager.h
|
||||
globalactionmanager.h
|
||||
contextmenu.h
|
||||
dropjob.h
|
||||
|
||||
artist.h
|
||||
album.h
|
||||
@@ -354,6 +357,7 @@ set( libHeaders
|
||||
|
||||
widgets/newplaylistwidget.h
|
||||
widgets/searchwidget.h
|
||||
widgets/SeekSlider.h
|
||||
widgets/playlisttypeselectordlg.h
|
||||
widgets/welcomewidget.h
|
||||
widgets/welcomeplaylistmodel.h
|
||||
@@ -406,7 +410,7 @@ include_directories( . ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/.
|
||||
|
||||
${LIBPORTFWD_INCLUDE_DIR}
|
||||
${THIRDPARTY_DIR}/qxt/qxtweb-standalone/qxtweb
|
||||
${CMAKE_BINARY_DIR}/thirdparty/liblastfm2/src
|
||||
|
||||
)
|
||||
|
||||
IF( UNIX AND NOT APPLE )
|
||||
@@ -416,6 +420,12 @@ IF( UNIX AND NOT APPLE )
|
||||
|
||||
SET( libHeaders ${libHeaders}
|
||||
infosystem/infoplugins/unix/fdonotifyplugin.h )
|
||||
|
||||
IF( BUILD_GUI AND X11_FOUND )
|
||||
INCLUDE_DIRECTORIES( ${THIRDPARTY_DIR}/libqnetwm )
|
||||
SET( libSources ${libSources} ${THIRDPARTY_DIR}/libqnetwm/libqnetwm/netwm.cpp )
|
||||
SET( LINK_LIBRARIES ${LINK_LIBRARIES} ${X11_LIBRARIES} )
|
||||
ENDIF()
|
||||
ENDIF( UNIX AND NOT APPLE )
|
||||
|
||||
IF( WIN32 )
|
||||
|
@@ -212,7 +212,7 @@ AudioEngine::next()
|
||||
return;
|
||||
|
||||
if ( !m_currentTrack.isNull() && !m_playlist.data()->hasNextItem() &&
|
||||
m_currentTrack->id() == m_playlist.data()->currentItem()->id() )
|
||||
( m_playlist.data()->currentItem().isNull() || ( m_currentTrack->id() == m_playlist.data()->currentItem()->id() ) ) )
|
||||
{
|
||||
//For instance, when doing a catch-up while listening along, but the person
|
||||
//you're following hasn't started a new track yet...don't do anything
|
||||
@@ -305,11 +305,17 @@ AudioEngine::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData,
|
||||
return;
|
||||
}
|
||||
|
||||
if ( m_currentTrack.isNull() ||
|
||||
m_currentTrack.data()->track().isNull() ||
|
||||
m_currentTrack.data()->artist().isNull() ||
|
||||
m_currentTrack.data()->album().isNull() )
|
||||
return;
|
||||
|
||||
QVariantMap playInfo;
|
||||
playInfo["message"] = QString( "Tomahawk is playing \"%1\" by %2 on album %3." )
|
||||
.arg( m_currentTrack->track() )
|
||||
.arg( m_currentTrack->artist()->name() )
|
||||
.arg( m_currentTrack->album()->name() );
|
||||
.arg( m_currentTrack->album()->name() );
|
||||
if ( !output.isNull() && output.isValid() )
|
||||
{
|
||||
QVariantMap returnedData = output.value< QVariantMap >();
|
||||
@@ -487,8 +493,6 @@ AudioEngine::playItem( Tomahawk::PlaylistInterface* playlist, const Tomahawk::re
|
||||
{
|
||||
tDebug( LOGEXTRA ) << Q_FUNC_INFO << ( result.isNull() ? QString() : result->url() );
|
||||
|
||||
if ( !result->isOnline() )
|
||||
return;
|
||||
if ( !m_playlist.isNull() )
|
||||
m_playlist.data()->reset();
|
||||
|
||||
|
@@ -27,6 +27,7 @@
|
||||
#include "databasecommand_collectionstats.h"
|
||||
#include "databaseimpl.h"
|
||||
#include "network/controlconnection.h"
|
||||
#include "sourcelist.h"
|
||||
|
||||
#include "utils/logger.h"
|
||||
|
||||
@@ -72,7 +73,15 @@ DatabaseCommand_AddFiles::postCommitHook()
|
||||
emit notify( m_queries );
|
||||
|
||||
if( source()->isLocal() )
|
||||
{
|
||||
Servent::instance()->triggerDBSync();
|
||||
|
||||
// Re-calculate local db stats
|
||||
DatabaseCommand_CollectionStats* cmd = new DatabaseCommand_CollectionStats( SourceList::instance()->getLocal() );
|
||||
connect( cmd, SIGNAL( done( QVariantMap ) ),
|
||||
SourceList::instance()->getLocal().data(), SLOT( setStats( QVariantMap ) ), Qt::QueuedConnection );
|
||||
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>( cmd ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@@ -74,8 +74,7 @@ DatabaseCommand_AllAlbums::execForArtist( DatabaseImpl* dbi )
|
||||
al << album;
|
||||
}
|
||||
|
||||
if ( al.count() )
|
||||
emit albums( al, data() );
|
||||
emit albums( al, data() );
|
||||
emit done();
|
||||
}
|
||||
|
||||
@@ -124,8 +123,7 @@ DatabaseCommand_AllAlbums::execForCollection( DatabaseImpl* dbi )
|
||||
al << album;
|
||||
}
|
||||
|
||||
if ( al.count() )
|
||||
emit albums( al, data() );
|
||||
emit albums( al, data() );
|
||||
emit done();
|
||||
}
|
||||
|
||||
|
@@ -26,6 +26,22 @@ DatabaseCommand_loadOps::exec( DatabaseImpl* dbi )
|
||||
{
|
||||
QList< dbop_ptr > ops;
|
||||
|
||||
if ( !m_since.isEmpty() )
|
||||
{
|
||||
TomahawkSqlQuery query = dbi->newquery();
|
||||
query.prepare( QString( "SELECT id FROM oplog WHERE guid = ?" ) );
|
||||
query.addBindValue( m_since );
|
||||
query.exec();
|
||||
|
||||
if ( !query.next() )
|
||||
{
|
||||
tLog() << "Unknown oplog guid, requested, not replying:" << m_since;
|
||||
Q_ASSERT( false );
|
||||
emit done( m_since, m_since, ops );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
TomahawkSqlQuery query = dbi->newquery();
|
||||
query.prepare( QString(
|
||||
"SELECT guid, command, json, compressed, singleton "
|
||||
|
@@ -110,6 +110,7 @@ DatabaseWorker::doWork()
|
||||
try
|
||||
{
|
||||
{
|
||||
tDebug() << "Executing cmd:" << cmd->guid();
|
||||
cmd->_exec( m_dbimpl ); // runs actual SQL stuff
|
||||
|
||||
if ( cmd->loggable() )
|
||||
|
362
src/libtomahawk/dropjob.cpp
Normal file
362
src/libtomahawk/dropjob.cpp
Normal file
@@ -0,0 +1,362 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2011, Michael Zanetti <mzanetti@kde.org>
|
||||
* Copyright 2011, Leo Franchi <lfranchi@kde.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dropjob.h"
|
||||
|
||||
#include "artist.h"
|
||||
#include "album.h"
|
||||
|
||||
#include "utils/spotifyparser.h"
|
||||
#include "utils/rdioparser.h"
|
||||
#include "utils/shortenedlinkparser.h"
|
||||
#include "utils/logger.h"
|
||||
#include "globalactionmanager.h"
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
DropJob::DropJob( QObject *parent )
|
||||
: QObject( parent )
|
||||
, m_queryCount( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
DropJob::~DropJob()
|
||||
{
|
||||
qDebug() << "destryong DropJob";
|
||||
}
|
||||
|
||||
/// QMIMEDATA HANDLING
|
||||
|
||||
QStringList
|
||||
DropJob::mimeTypes()
|
||||
{
|
||||
QStringList mimeTypes;
|
||||
mimeTypes << "application/tomahawk.query.list"
|
||||
<< "application/tomahawk.plentry.list"
|
||||
<< "application/tomahawk.result.list"
|
||||
<< "application/tomahawk.result"
|
||||
<< "application/tomahawk.metadata.artist"
|
||||
<< "application/tomahawk.metadata.album"
|
||||
<< "application/tomahawk.mixed"
|
||||
<< "text/plain";
|
||||
return mimeTypes;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
DropJob::acceptsMimeData( const QMimeData* data, bool tracksOnly )
|
||||
{
|
||||
if ( data->hasFormat( "application/tomahawk.query.list" )
|
||||
|| data->hasFormat( "application/tomahawk.plentry.list" )
|
||||
|| data->hasFormat( "application/tomahawk.result.list" )
|
||||
|| data->hasFormat( "application/tomahawk.result" )
|
||||
|| data->hasFormat( "application/tomahawk.mixed" )
|
||||
|| data->hasFormat( "application/tomahawk.metadata.album" )
|
||||
|| data->hasFormat( "application/tomahawk.metadata.artist" ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// crude check for spotify tracks
|
||||
if ( data->hasFormat( "text/plain" ) && data->data( "text/plain" ).contains( "spotify" ) &&
|
||||
( tracksOnly ? data->data( "text/plain" ).contains( "track" ) : true ) )
|
||||
return true;
|
||||
|
||||
// crude check for rdio tracks
|
||||
if ( data->hasFormat( "text/plain" ) && data->data( "text/plain" ).contains( "rdio.com" ) &&
|
||||
( tracksOnly ? data->data( "text/plain" ).contains( "track" ) : true ) )
|
||||
return true;
|
||||
|
||||
// We whitelist t.co and bit.ly (and j.mp) since they do some link checking. Often playable (e.g. spotify..) links hide behind them,
|
||||
// so we do an extra level of lookup
|
||||
if ( ( data->hasFormat( "text/plain" ) && data->data( "text/plain" ).contains( "bit.ly" ) ) ||
|
||||
( data->hasFormat( "text/plain" ) && data->data( "text/plain" ).contains( "j.mp" ) ) ||
|
||||
( data->hasFormat( "text/plain" ) && data->data( "text/plain" ).contains( "t.co" ) ) ||
|
||||
( data->hasFormat( "text/plain" ) && data->data( "text/plain" ).contains( "rd.io" ) ) )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DropJob::tracksFromMimeData( const QMimeData* data, bool allowDuplicates )
|
||||
{
|
||||
m_allowDuplicates = allowDuplicates;
|
||||
|
||||
parseMimeData( data );
|
||||
|
||||
if ( m_queryCount == 0 )
|
||||
{
|
||||
if ( !allowDuplicates )
|
||||
removeDuplicates();
|
||||
|
||||
emit tracks( m_resultList );
|
||||
deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DropJob::parseMimeData( const QMimeData *data )
|
||||
{
|
||||
QList< query_ptr > results;
|
||||
if ( data->hasFormat( "application/tomahawk.query.list" ) )
|
||||
results = tracksFromQueryList( data );
|
||||
else if ( data->hasFormat( "application/tomahawk.result.list" ) )
|
||||
results = tracksFromResultList( data );
|
||||
else if ( data->hasFormat( "application/tomahawk.metadata.album" ) )
|
||||
results = tracksFromAlbumMetaData( data );
|
||||
else if ( data->hasFormat( "application/tomahawk.metadata.artist" ) )
|
||||
results = tracksFromArtistMetaData( data );
|
||||
else if ( data->hasFormat( "application/tomahawk.mixed" ) )
|
||||
tracksFromMixedData( data );
|
||||
else if ( data->hasFormat( "text/plain" ) )
|
||||
{
|
||||
QString plainData = QString::fromUtf8( data->data( "text/plain" ).constData() );
|
||||
tDebug() << "Got text/plain mime data:" << data->data( "text/plain" ) << "decoded to:" << plainData;
|
||||
handleTrackUrls ( plainData );
|
||||
}
|
||||
|
||||
m_resultList.append( results );
|
||||
}
|
||||
|
||||
QList< query_ptr >
|
||||
DropJob::tracksFromQueryList( const QMimeData* data )
|
||||
{
|
||||
QList< query_ptr > queries;
|
||||
QByteArray itemData = data->data( "application/tomahawk.query.list" );
|
||||
QDataStream stream( &itemData, QIODevice::ReadOnly );
|
||||
|
||||
while ( !stream.atEnd() )
|
||||
{
|
||||
qlonglong qptr;
|
||||
stream >> qptr;
|
||||
|
||||
query_ptr* query = reinterpret_cast<query_ptr*>(qptr);
|
||||
if ( query && !query->isNull() )
|
||||
{
|
||||
tDebug() << "Dropped query item:" << query->data()->artist() << "-" << query->data()->track();
|
||||
queries << *query;
|
||||
}
|
||||
}
|
||||
|
||||
return queries;
|
||||
}
|
||||
|
||||
QList< query_ptr >
|
||||
DropJob::tracksFromResultList( const QMimeData* data )
|
||||
{
|
||||
QList< query_ptr > queries;
|
||||
QByteArray itemData = data->data( "application/tomahawk.result.list" );
|
||||
QDataStream stream( &itemData, QIODevice::ReadOnly );
|
||||
|
||||
while ( !stream.atEnd() )
|
||||
{
|
||||
qlonglong qptr;
|
||||
stream >> qptr;
|
||||
|
||||
result_ptr* result = reinterpret_cast<result_ptr*>(qptr);
|
||||
if ( result && !result->isNull() )
|
||||
{
|
||||
tDebug() << "Dropped result item:" << result->data()->artist()->name() << "-" << result->data()->track();
|
||||
query_ptr q = result->data()->toQuery();
|
||||
q->addResults( QList< result_ptr >() << *result );
|
||||
queries << q;
|
||||
}
|
||||
}
|
||||
|
||||
return queries;
|
||||
}
|
||||
|
||||
QList< query_ptr >
|
||||
DropJob::tracksFromAlbumMetaData( const QMimeData *data )
|
||||
{
|
||||
QList<query_ptr> queries;
|
||||
QByteArray itemData = data->data( "application/tomahawk.metadata.album" );
|
||||
QDataStream stream( &itemData, QIODevice::ReadOnly );
|
||||
|
||||
while ( !stream.atEnd() )
|
||||
{
|
||||
QString artist;
|
||||
stream >> artist;
|
||||
QString album;
|
||||
stream >> album;
|
||||
|
||||
artist_ptr artistPtr = Artist::get( artist );
|
||||
album_ptr albumPtr = Album::get( artistPtr, album );
|
||||
if ( albumPtr->tracks().isEmpty() )
|
||||
{
|
||||
connect( albumPtr.data(), SIGNAL( tracksAdded( QList<Tomahawk::query_ptr> ) ),
|
||||
SLOT( onTracksAdded( QList<Tomahawk::query_ptr> ) ) );
|
||||
m_queryCount++;
|
||||
}
|
||||
else
|
||||
queries << albumPtr->tracks();
|
||||
}
|
||||
return queries;
|
||||
}
|
||||
|
||||
QList< query_ptr >
|
||||
DropJob::tracksFromArtistMetaData( const QMimeData *data )
|
||||
{
|
||||
QList<query_ptr> queries;
|
||||
QByteArray itemData = data->data( "application/tomahawk.metadata.artist" );
|
||||
QDataStream stream( &itemData, QIODevice::ReadOnly );
|
||||
|
||||
while ( !stream.atEnd() )
|
||||
{
|
||||
QString artist;
|
||||
stream >> artist;
|
||||
|
||||
artist_ptr artistPtr = Artist::get( artist );
|
||||
if ( artistPtr->tracks().isEmpty() )
|
||||
{
|
||||
connect( artistPtr.data(), SIGNAL( tracksAdded( QList<Tomahawk::query_ptr> ) ),
|
||||
SLOT( onTracksAdded( QList<Tomahawk::query_ptr> ) ) );
|
||||
m_queryCount++;
|
||||
}
|
||||
else
|
||||
queries << artistPtr->tracks();
|
||||
}
|
||||
return queries;
|
||||
}
|
||||
|
||||
QList< query_ptr >
|
||||
DropJob::tracksFromMixedData( const QMimeData *data )
|
||||
{
|
||||
QList< query_ptr > queries;
|
||||
QByteArray itemData = data->data( "application/tomahawk.mixed" );
|
||||
QDataStream stream( &itemData, QIODevice::ReadOnly );
|
||||
|
||||
QString mimeType;
|
||||
|
||||
while ( !stream.atEnd() )
|
||||
{
|
||||
stream >> mimeType;
|
||||
qDebug() << "mimetype is" << mimeType;
|
||||
|
||||
QByteArray singleData;
|
||||
QDataStream singleStream( &singleData, QIODevice::WriteOnly );
|
||||
|
||||
QMimeData singleMimeData;
|
||||
if ( mimeType == "application/tomahawk.query.list" || mimeType == "application/tomahawk.result.list" )
|
||||
{
|
||||
qlonglong query;
|
||||
stream >> query;
|
||||
singleStream << query;
|
||||
}
|
||||
else if ( mimeType == "application/tomahawk.metadata.album" )
|
||||
{
|
||||
QString artist;
|
||||
stream >> artist;
|
||||
singleStream << artist;
|
||||
QString album;
|
||||
stream >> album;
|
||||
singleStream << album;
|
||||
qDebug() << "got artist" << artist << "and album" << album;
|
||||
}
|
||||
else if ( mimeType == "application/tomahawk.metadata.artist" )
|
||||
{
|
||||
QString artist;
|
||||
stream >> artist;
|
||||
singleStream << artist;
|
||||
qDebug() << "got artist" << artist;
|
||||
}
|
||||
|
||||
singleMimeData.setData( mimeType, singleData );
|
||||
parseMimeData( &singleMimeData );
|
||||
}
|
||||
return queries;
|
||||
}
|
||||
|
||||
void
|
||||
DropJob::handleTrackUrls( const QString& urls )
|
||||
{
|
||||
if ( urls.contains( "open.spotify.com/track") ||
|
||||
urls.contains( "spotify:track" ) )
|
||||
{
|
||||
QStringList tracks = urls.split( "\n" );
|
||||
|
||||
tDebug() << "Got a list of spotify urls!" << tracks;
|
||||
SpotifyParser* spot = new SpotifyParser( tracks, this );
|
||||
connect( spot, SIGNAL( tracks( QList<Tomahawk::query_ptr> ) ), this, SLOT( onTracksAdded( QList< Tomahawk::query_ptr > ) ) );
|
||||
m_queryCount++;
|
||||
} else if ( urls.contains( "rdio.com" ) )
|
||||
{
|
||||
QStringList tracks = urls.split( "\n" );
|
||||
|
||||
tDebug() << "Got a list of rdio urls!" << tracks;
|
||||
RdioParser* rdio = new RdioParser( this );
|
||||
connect( rdio, SIGNAL( tracks( QList<Tomahawk::query_ptr> ) ), this, SLOT( onTracksAdded( QList< Tomahawk::query_ptr > ) ) );
|
||||
m_queryCount++;
|
||||
rdio->parse( tracks );
|
||||
} else if ( urls.contains( "bit.ly" ) ||
|
||||
urls.contains( "j.mp" ) ||
|
||||
urls.contains( "t.co" ) ||
|
||||
urls.contains( "rd.io" ) )
|
||||
{
|
||||
QStringList tracks = urls.split( "\n" );
|
||||
|
||||
tDebug() << "Got a list of shortened urls!" << tracks;
|
||||
ShortenedLinkParser* parser = new ShortenedLinkParser( tracks, this );
|
||||
connect( parser, SIGNAL( urls( QStringList ) ), this, SLOT( expandedUrls( QStringList ) ) );
|
||||
m_queryCount++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DropJob::expandedUrls( QStringList urls )
|
||||
{
|
||||
m_queryCount--;
|
||||
handleTrackUrls( urls.join( "\n" ) );
|
||||
}
|
||||
|
||||
void
|
||||
DropJob::onTracksAdded( const QList<Tomahawk::query_ptr>& tracksList )
|
||||
{
|
||||
m_resultList.append( tracksList );
|
||||
|
||||
if ( --m_queryCount == 0 )
|
||||
{
|
||||
if ( !m_allowDuplicates )
|
||||
removeDuplicates();
|
||||
|
||||
emit tracks( m_resultList );
|
||||
deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DropJob::removeDuplicates()
|
||||
{
|
||||
QList< Tomahawk::query_ptr > list;
|
||||
foreach ( const Tomahawk::query_ptr& item, m_resultList )
|
||||
{
|
||||
bool contains = false;
|
||||
foreach( const Tomahawk::query_ptr &tmpItem, list )
|
||||
if ( item->album() == tmpItem->album()
|
||||
&& item->artist() == tmpItem->artist()
|
||||
&& item->track() == tmpItem->track() )
|
||||
contains = true;
|
||||
if ( !contains )
|
||||
list.append( item );
|
||||
}
|
||||
m_resultList = list;
|
||||
}
|
76
src/libtomahawk/dropjob.h
Normal file
76
src/libtomahawk/dropjob.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2011, Michael Zanetti <mzanetti@kde.org>
|
||||
* Copyright 2011, Leo Franchi <lfranchi@kde.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef DROPJOB_H
|
||||
#define DROPJOB_H
|
||||
|
||||
#include "query.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QStringList>
|
||||
#include <QMimeData>
|
||||
|
||||
class DLLEXPORT DropJob : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit DropJob( QObject *parent = 0 );
|
||||
~DropJob();
|
||||
|
||||
/**
|
||||
* QMimeData helpers
|
||||
*
|
||||
* Call this to parse the tracks in a QMimeData object to query_ptrs. This will parse internal tomahawk
|
||||
* data as well as all other formats supported (spotify, etc).
|
||||
*
|
||||
* Connect to tracks( QList< query_ptr> ); for the extracted tracks.
|
||||
*/
|
||||
static bool acceptsMimeData( const QMimeData* data, bool tracksOnly = true );
|
||||
static QStringList mimeTypes();
|
||||
void tracksFromMimeData( const QMimeData* data, bool allowDuplicates = false );
|
||||
|
||||
signals:
|
||||
/// QMimeData parsing results
|
||||
void tracks( const QList< Tomahawk::query_ptr >& tracks );
|
||||
|
||||
private slots:
|
||||
void expandedUrls( QStringList );
|
||||
|
||||
void onTracksAdded( const QList<Tomahawk::query_ptr>& );
|
||||
|
||||
private:
|
||||
/// handle parsing mime data
|
||||
void parseMimeData( const QMimeData* data );
|
||||
|
||||
void handleTrackUrls( const QString& urls );
|
||||
QList< Tomahawk::query_ptr > tracksFromQueryList( const QMimeData* d );
|
||||
QList< Tomahawk::query_ptr > tracksFromResultList( const QMimeData* d );
|
||||
QList< Tomahawk::query_ptr > tracksFromArtistMetaData( const QMimeData* d );
|
||||
QList< Tomahawk::query_ptr > tracksFromAlbumMetaData( const QMimeData* d );
|
||||
QList< Tomahawk::query_ptr > tracksFromMixedData( const QMimeData* d );
|
||||
|
||||
void removeDuplicates();
|
||||
|
||||
int m_queryCount;
|
||||
bool m_allowDuplicates;
|
||||
|
||||
QList< Tomahawk::query_ptr > m_resultList;
|
||||
};
|
||||
|
||||
#endif // DROPJOB_H
|
@@ -64,7 +64,6 @@ GlobalActionManager::instance()
|
||||
GlobalActionManager::GlobalActionManager( QObject* parent )
|
||||
: QObject( parent )
|
||||
{
|
||||
m_mimeTypes << "application/tomahawk.query.list" << "application/tomahawk.plentry.list" << "application/tomahawk.result.list" << "text/plain";
|
||||
}
|
||||
|
||||
GlobalActionManager::~GlobalActionManager()
|
||||
@@ -779,149 +778,6 @@ GlobalActionManager::hostname() const
|
||||
return QString( "http://toma.hk" );
|
||||
}
|
||||
|
||||
/// QMIMEDATA HANDLING
|
||||
|
||||
QStringList
|
||||
GlobalActionManager::mimeTypes() const
|
||||
{
|
||||
return m_mimeTypes;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
GlobalActionManager::acceptsMimeData( const QMimeData* data, bool tracksOnly )
|
||||
{
|
||||
if ( data->hasFormat( "application/tomahawk.query.list" )
|
||||
|| data->hasFormat( "application/tomahawk.plentry.list" )
|
||||
|| data->hasFormat( "application/tomahawk.result.list" ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// crude check for spotify tracks
|
||||
if ( data->hasFormat( "text/plain" ) && data->data( "text/plain" ).contains( "spotify" ) &&
|
||||
( tracksOnly ? data->data( "text/plain" ).contains( "track" ) : true ) )
|
||||
return true;
|
||||
|
||||
// crude check for rdio tracks
|
||||
if ( data->hasFormat( "text/plain" ) && data->data( "text/plain" ).contains( "rdio.com" ) &&
|
||||
( tracksOnly ? data->data( "text/plain" ).contains( "track" ) : true ) )
|
||||
return true;
|
||||
|
||||
// We whitelist t.co and bit.ly (and j.mp) since they do some link checking. Often playable (e.g. spotify..) links hide behind them,
|
||||
// so we do an extra level of lookup
|
||||
if ( ( data->hasFormat( "text/plain" ) && data->data( "text/plain" ).contains( "bit.ly" ) ) ||
|
||||
( data->hasFormat( "text/plain" ) && data->data( "text/plain" ).contains( "j.mp" ) ) ||
|
||||
( data->hasFormat( "text/plain" ) && data->data( "text/plain" ).contains( "t.co" ) ) ||
|
||||
( data->hasFormat( "text/plain" ) && data->data( "text/plain" ).contains( "rd.io" ) ) )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GlobalActionManager::tracksFromMimeData( const QMimeData* data )
|
||||
{
|
||||
if ( data->hasFormat( "application/tomahawk.query.list" ) )
|
||||
emit tracks( tracksFromQueryList( data ) );
|
||||
else if ( data->hasFormat( "application/tomahawk.result.list" ) )
|
||||
emit tracks( tracksFromResultList( data ) );
|
||||
else if ( data->hasFormat( "text/plain" ) )
|
||||
{
|
||||
QString plainData = QString::fromUtf8( data->data( "text/plain" ).constData() );
|
||||
tDebug() << "Got text/plain mime data:" << data->data( "text/plain" ) << "decoded to:" << plainData;
|
||||
handleTrackUrls ( plainData );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GlobalActionManager::handleTrackUrls( const QString& urls )
|
||||
{
|
||||
if ( urls.contains( "open.spotify.com/track") ||
|
||||
urls.contains( "spotify:track" ) )
|
||||
{
|
||||
QStringList tracks = urls.split( "\n" );
|
||||
|
||||
tDebug() << "Got a list of spotify urls!" << tracks;
|
||||
SpotifyParser* spot = new SpotifyParser( tracks, this );
|
||||
connect( spot, SIGNAL( tracks( QList<Tomahawk::query_ptr> ) ), this, SIGNAL( tracks( QList<Tomahawk::query_ptr> ) ) );
|
||||
} else if ( urls.contains( "rdio.com" ) )
|
||||
{
|
||||
QStringList tracks = urls.split( "\n" );
|
||||
|
||||
tDebug() << "Got a list of rdio urls!" << tracks;
|
||||
RdioParser* rdio = new RdioParser( this );
|
||||
connect( rdio, SIGNAL( tracks( QList<Tomahawk::query_ptr> ) ), this, SIGNAL( tracks( QList<Tomahawk::query_ptr> ) ) );
|
||||
rdio->parse( tracks );
|
||||
} else if ( urls.contains( "bit.ly" ) ||
|
||||
urls.contains( "j.mp" ) ||
|
||||
urls.contains( "t.co" ) ||
|
||||
urls.contains( "rd.io" ) )
|
||||
{
|
||||
QStringList tracks = urls.split( "\n" );
|
||||
|
||||
tDebug() << "Got a list of shortened urls!" << tracks;
|
||||
ShortenedLinkParser* parser = new ShortenedLinkParser( tracks, this );
|
||||
connect( parser, SIGNAL( urls( QStringList ) ), this, SLOT( expandedUrls( QStringList ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
GlobalActionManager::expandedUrls( QStringList urls )
|
||||
{
|
||||
handleTrackUrls( urls.join( "\n" ) );
|
||||
}
|
||||
|
||||
|
||||
QList< query_ptr >
|
||||
GlobalActionManager::tracksFromQueryList( const QMimeData* data )
|
||||
{
|
||||
QList< query_ptr > queries;
|
||||
QByteArray itemData = data->data( "application/tomahawk.query.list" );
|
||||
QDataStream stream( &itemData, QIODevice::ReadOnly );
|
||||
|
||||
while ( !stream.atEnd() )
|
||||
{
|
||||
qlonglong qptr;
|
||||
stream >> qptr;
|
||||
|
||||
query_ptr* query = reinterpret_cast<query_ptr*>(qptr);
|
||||
if ( query && !query->isNull() )
|
||||
{
|
||||
tDebug() << "Dropped query item:" << query->data()->artist() << "-" << query->data()->track();
|
||||
queries << *query;
|
||||
}
|
||||
}
|
||||
|
||||
return queries;
|
||||
}
|
||||
|
||||
QList< query_ptr >
|
||||
GlobalActionManager::tracksFromResultList( const QMimeData* data )
|
||||
{
|
||||
QList< query_ptr > queries;
|
||||
QByteArray itemData = data->data( "application/tomahawk.result.list" );
|
||||
QDataStream stream( &itemData, QIODevice::ReadOnly );
|
||||
|
||||
while ( !stream.atEnd() )
|
||||
{
|
||||
qlonglong qptr;
|
||||
stream >> qptr;
|
||||
|
||||
result_ptr* result = reinterpret_cast<result_ptr*>(qptr);
|
||||
if ( result && !result->isNull() )
|
||||
{
|
||||
tDebug() << "Dropped result item:" << result->data()->artist()->name() << "-" << result->data()->track();
|
||||
query_ptr q = result->data()->toQuery();
|
||||
q->addResults( QList< result_ptr >() << *result );
|
||||
queries << q;
|
||||
}
|
||||
}
|
||||
|
||||
return queries;
|
||||
}
|
||||
|
||||
/// SPOTIFY URL HANDLING
|
||||
|
||||
|
@@ -51,18 +51,6 @@ public:
|
||||
QString copyPlaylistToClipboard( const Tomahawk::dynplaylist_ptr& playlist );
|
||||
void savePlaylistToFile( const Tomahawk::playlist_ptr& playlist, const QString& filename );
|
||||
|
||||
/**
|
||||
* QMimeData helpers
|
||||
*
|
||||
* Call this to parse the tracks in a QMimeData object to query_ptrs. This will parse internal tomahawk
|
||||
* data as well as all other formats supported (spotify, etc).
|
||||
*
|
||||
* Connect to tracks( QList< query_ptr> ); for the extracted tracks.
|
||||
*/
|
||||
bool acceptsMimeData( const QMimeData* data, bool tracksOnly = true );
|
||||
void tracksFromMimeData( const QMimeData* data );
|
||||
QStringList mimeTypes() const;
|
||||
|
||||
public slots:
|
||||
bool parseTomahawkLink( const QString& link );
|
||||
void waitingForResolved( bool );
|
||||
@@ -70,16 +58,12 @@ public slots:
|
||||
Tomahawk::dynplaylist_ptr loadDynamicPlaylist( const QUrl& url, bool station );
|
||||
|
||||
void handleOpenTrack( const Tomahawk::query_ptr& qry );
|
||||
signals:
|
||||
/// QMimeData parsing results
|
||||
void tracks( const QList< Tomahawk::query_ptr >& tracks );
|
||||
|
||||
private slots:
|
||||
void bookmarkPlaylistCreated( const Tomahawk::playlist_ptr& pl );
|
||||
void showPlaylist();
|
||||
|
||||
void xspfCreated( const QByteArray& xspf );
|
||||
void expandedUrls( QStringList );
|
||||
|
||||
void spotifyToPlay( const Tomahawk::query_ptr& );
|
||||
private:
|
||||
@@ -101,18 +85,12 @@ private:
|
||||
bool playSpotify( const QUrl& url );
|
||||
bool queueSpotify( const QStringList& parts, const QList< QPair< QString, QString > >& queryItems );
|
||||
|
||||
/// handle parsing mime data
|
||||
void handleTrackUrls( const QString& urls );
|
||||
QList< Tomahawk::query_ptr > tracksFromQueryList( const QMimeData* d );
|
||||
QList< Tomahawk::query_ptr > tracksFromResultList( const QMimeData* d );
|
||||
|
||||
QString hostname() const;
|
||||
|
||||
Tomahawk::playlist_ptr m_toShow;
|
||||
Tomahawk::query_ptr m_waitingToBookmark;
|
||||
Tomahawk::query_ptr m_waitingToPlay;
|
||||
|
||||
QStringList m_mimeTypes;
|
||||
static GlobalActionManager* s_instance;
|
||||
};
|
||||
|
||||
|
@@ -283,7 +283,7 @@ DBSyncConnection::lastOpApplied()
|
||||
void
|
||||
DBSyncConnection::sendOps()
|
||||
{
|
||||
tLog() << "Will send peer all ops since" << m_uscache.value( "lastop" ).toString();
|
||||
tLog() << "Will send peer" << m_source->id() << "all ops since" << m_uscache.value( "lastop" ).toString();
|
||||
|
||||
source_ptr src = SourceList::instance()->getLocal();
|
||||
|
||||
|
@@ -60,6 +60,7 @@ Servent::Servent( QObject* parent )
|
||||
: QTcpServer( parent )
|
||||
, m_port( 0 )
|
||||
, m_externalPort( 0 )
|
||||
, m_ready( false )
|
||||
, m_portfwd( 0 )
|
||||
{
|
||||
s_instance = this;
|
||||
@@ -133,6 +134,7 @@ Servent::startListening( QHostAddress ha, bool upnp, int port )
|
||||
tLog() << "Forcing static preferred host and port";
|
||||
m_externalHostname = TomahawkSettings::instance()->externalHostname();
|
||||
m_externalPort = TomahawkSettings::instance()->externalPort();
|
||||
m_ready = true;
|
||||
emit ready();
|
||||
return true;
|
||||
}
|
||||
@@ -151,11 +153,14 @@ Servent::startListening( QHostAddress ha, bool upnp, int port )
|
||||
|
||||
if ( qApp->arguments().contains( "--lanhack" ) )
|
||||
{
|
||||
qDebug() << "LANHACK: set external address to lan address" << ha.toString();
|
||||
tLog() << "LANHACK: set external address to lan address" << ha.toString();
|
||||
QMetaObject::invokeMethod( this, "setExternalAddress", Qt::QueuedConnection, Q_ARG( QHostAddress, ha ), Q_ARG( unsigned int, m_port ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ready = true;
|
||||
emit ready();
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -186,7 +191,7 @@ Servent::createConnectionKey( const QString& name, const QString &nodeid, const
|
||||
cc->setId( nodeid );
|
||||
cc->setOnceOnly( onceOnly );
|
||||
|
||||
qDebug() << "Creating connection key with name of " << cc->name() << " and id of " << cc->id() << " and key of " << _key << "; key is once only? : " << (onceOnly ? "true" : "false");
|
||||
qDebug() << "Creating connection key with name of" << cc->name() << "and id of" << cc->id() << "and key of" << _key << "; key is once only? :" << (onceOnly ? "true" : "false");
|
||||
registerOffer( _key, cc );
|
||||
return _key;
|
||||
}
|
||||
@@ -224,9 +229,10 @@ Servent::setExternalAddress( QHostAddress ha, unsigned int port )
|
||||
qDebug() << m_externalHostname << m_externalPort;
|
||||
}
|
||||
else
|
||||
qDebug() << "No external access, LAN and outbound connections only!";
|
||||
tLog() << "No external access, LAN and outbound connections only!";
|
||||
}
|
||||
|
||||
m_ready = true;
|
||||
emit ready();
|
||||
}
|
||||
|
||||
@@ -348,7 +354,7 @@ Servent::readyRead()
|
||||
// qDebug() << con->socket() << sock;
|
||||
if( con->id() == nodeid )
|
||||
{
|
||||
qDebug() << "Duplicate control connection detected, dropping:" << nodeid << conntype;
|
||||
tLog() << "Duplicate control connection detected, dropping:" << nodeid << conntype;
|
||||
goto closeconnection;
|
||||
}
|
||||
}
|
||||
@@ -372,7 +378,7 @@ Servent::readyRead()
|
||||
Connection* conn = claimOffer( cc, nodeid, key, sock->peerAddress() );
|
||||
if( !conn )
|
||||
{
|
||||
qDebug() << "claimOffer FAILED, key:" << key;
|
||||
tLog() << "claimOffer FAILED, key:" << key;
|
||||
goto closeconnection;
|
||||
}
|
||||
qDebug() << "claimOffer OK:" << key;
|
||||
@@ -390,7 +396,7 @@ Servent::readyRead()
|
||||
|
||||
// fallthru to cleanup:
|
||||
closeconnection:
|
||||
qDebug() << "Closing incoming connection, something was wrong.";
|
||||
tLog() << "Closing incoming connection, something was wrong.";
|
||||
sock->_msg.clear();
|
||||
sock->disconnectFromHost();
|
||||
}
|
||||
@@ -405,7 +411,7 @@ Servent::createParallelConnection( Connection* orig_conn, Connection* new_conn,
|
||||
// if we can connect to them directly:
|
||||
if( orig_conn && orig_conn->outbound() )
|
||||
{
|
||||
qDebug() << "Connecting directly";
|
||||
tLog() << "Connecting directly";
|
||||
connectToPeer( orig_conn->socket()->peerAddress().toString(),
|
||||
orig_conn->peerPort(),
|
||||
key,
|
||||
@@ -414,7 +420,7 @@ Servent::createParallelConnection( Connection* orig_conn, Connection* new_conn,
|
||||
else // ask them to connect to us:
|
||||
{
|
||||
QString tmpkey = uuid();
|
||||
qDebug() << "Asking them to connect to us using" << tmpkey ;
|
||||
tLog() << "Asking them to connect to us using" << tmpkey ;
|
||||
registerOffer( tmpkey, new_conn );
|
||||
|
||||
QVariantMap m;
|
||||
@@ -470,12 +476,18 @@ Servent::socketError( QAbstractSocket::SocketError e )
|
||||
QTcpSocketExtra* sock = (QTcpSocketExtra*)sender();
|
||||
if( !sock )
|
||||
{
|
||||
qDebug() << "SocketError, sock is null";
|
||||
tLog() << "SocketError, sock is null";
|
||||
return;
|
||||
}
|
||||
|
||||
Connection* conn = sock->_conn;
|
||||
qDebug() << "Servent::SocketError:" << e << conn->id() << conn->name();
|
||||
if ( !conn )
|
||||
{
|
||||
tLog() << "SocketError, connection is null";
|
||||
return;
|
||||
}
|
||||
|
||||
tLog() << "Servent::SocketError:" << e << conn->id() << conn->name();
|
||||
if( !sock->_disowned )
|
||||
{
|
||||
// connection will delete if we already transferred ownership, otherwise:
|
||||
@@ -601,7 +613,7 @@ Servent::claimOffer( ControlConnection* cc, const QString &nodeid, const QString
|
||||
}
|
||||
if( !authed )
|
||||
{
|
||||
qDebug() << "File transfer request rejected, invalid source IP";
|
||||
tLog() << "File transfer request rejected, invalid source IP";
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@@ -635,7 +647,7 @@ Servent::claimOffer( ControlConnection* cc, const QString &nodeid, const QString
|
||||
// This can happen if it's a streamconnection, but the audioengine has
|
||||
// already closed the iodevice, causing the connection to be deleted before
|
||||
// the peer connects and provides the first byte
|
||||
qDebug() << Q_FUNC_INFO << "invalid/expired offer:" << key;
|
||||
tLog() << Q_FUNC_INFO << "invalid/expired offer:" << key;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -644,12 +656,12 @@ Servent::claimOffer( ControlConnection* cc, const QString &nodeid, const QString
|
||||
// If there isn't a nodeid it's not the first connection and will already have been stopped
|
||||
if( !checkACL( conn, nodeid, true ) )
|
||||
{
|
||||
qDebug() << "Connection not allowed due to ACL";
|
||||
tLog() << "Connection not allowed due to ACL";
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
qDebug() << "ACL has allowed the connection";
|
||||
tLog() << "ACL has allowed the connection";
|
||||
|
||||
if( conn->onceOnly() )
|
||||
{
|
||||
@@ -670,7 +682,7 @@ Servent::claimOffer( ControlConnection* cc, const QString &nodeid, const QString
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "Invalid offer key:" << key;
|
||||
tLog() << "Invalid offer key:" << key;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@@ -823,7 +835,6 @@ Servent::isIPWhitelisted( QHostAddress ip )
|
||||
bool
|
||||
Servent::connectedToSession( const QString& session )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
// qDebug() << "Checking against" << session;
|
||||
foreach( ControlConnection* cc, m_controlconnections )
|
||||
{
|
||||
@@ -839,8 +850,6 @@ Servent::connectedToSession( const QString& session )
|
||||
void
|
||||
Servent::triggerDBSync()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
|
||||
// tell peers we have new stuff they should sync
|
||||
QList<source_ptr> sources = SourceList::instance()->sources();
|
||||
foreach( const source_ptr& src, sources )
|
||||
@@ -866,7 +875,6 @@ Servent::registerIODeviceFactory( const QString &proto, boost::function<QSharedP
|
||||
QSharedPointer<QIODevice>
|
||||
Servent::getIODeviceForUrl( const Tomahawk::result_ptr& result )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << thread();
|
||||
QSharedPointer<QIODevice> sp;
|
||||
|
||||
QRegExp rx( "^([a-zA-Z0-9]+)://(.+)$" );
|
||||
@@ -897,7 +905,6 @@ Servent::localFileIODeviceFactory( const Tomahawk::result_ptr& result )
|
||||
QSharedPointer<QIODevice>
|
||||
Servent::httpIODeviceFactory( const Tomahawk::result_ptr& result )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << result->url();
|
||||
QNetworkRequest req( result->url() );
|
||||
QNetworkReply* reply = TomahawkUtils::nam()->get( req );
|
||||
return QSharedPointer<QIODevice>( reply, &QObject::deleteLater );
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
@@ -123,6 +123,8 @@ public:
|
||||
QSharedPointer<QIODevice> localFileIODeviceFactory( const Tomahawk::result_ptr& result );
|
||||
QSharedPointer<QIODevice> httpIODeviceFactory( const Tomahawk::result_ptr& result );
|
||||
|
||||
bool isReady() const { return m_ready; };
|
||||
|
||||
signals:
|
||||
void streamStarted( StreamConnection* );
|
||||
void streamFinished( StreamConnection* );
|
||||
@@ -159,6 +161,7 @@ private:
|
||||
int m_port, m_externalPort;
|
||||
QHostAddress m_externalAddress;
|
||||
QString m_externalHostname;
|
||||
bool m_ready;
|
||||
|
||||
// currently active file transfers:
|
||||
QList< StreamConnection* > m_scsessions;
|
||||
|
@@ -116,11 +116,13 @@ Pipeline::resolve( const QList<query_ptr>& qlist, bool prioritized, bool tempora
|
||||
int i = 0;
|
||||
foreach( const query_ptr& q, qlist )
|
||||
{
|
||||
if ( !m_qids.contains( q->id() ) )
|
||||
m_qids.insert( q->id(), q );
|
||||
|
||||
if ( m_queries_pending.contains( q ) )
|
||||
continue;
|
||||
if ( m_qidsState.contains( q->id() ) )
|
||||
continue;
|
||||
|
||||
if ( !m_qids.contains( q->id() ) )
|
||||
m_qids.insert( q->id(), q );
|
||||
|
||||
if ( prioritized )
|
||||
m_queries_pending.insert( i++, q );
|
||||
@@ -169,8 +171,7 @@ Pipeline::reportResults( QID qid, const QList< result_ptr >& results )
|
||||
|
||||
if ( !m_qids.contains( qid ) )
|
||||
{
|
||||
qDebug() << "reportResults called for unknown QID" << qid;
|
||||
Q_ASSERT( false );
|
||||
tDebug() << "Result arrived too late for:" << qid;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -183,35 +184,14 @@ Pipeline::reportResults( QID qid, const QList< result_ptr >& results )
|
||||
m_rids.insert( r->id(), r );
|
||||
}
|
||||
|
||||
if ( q->solved() && !q->isFullTextQuery() )
|
||||
if ( q->playable() && !q->isFullTextQuery() )
|
||||
{
|
||||
q->onResolvingFinished();
|
||||
|
||||
setQIDState( q, 0 );
|
||||
if ( m_qidsTimeout.contains( q->id() ) )
|
||||
m_qidsTimeout.remove( q->id() );
|
||||
|
||||
shuntNext();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ( decQIDState( q ) == 0 )
|
||||
{
|
||||
if ( !q->solved() || q->isFullTextQuery() )
|
||||
q->onResolvingFinished();
|
||||
|
||||
if ( !m_queries_temporary.contains( q ) )
|
||||
m_qids.remove( q->id() );
|
||||
if ( m_qidsTimeout.contains( q->id() ) )
|
||||
m_qidsTimeout.remove( q->id() );
|
||||
|
||||
shuntNext();
|
||||
}
|
||||
else
|
||||
{
|
||||
new FuncTimeout( 0, boost::bind( &Pipeline::timeoutShunt, this, q ), this );
|
||||
}
|
||||
decQIDState( q );
|
||||
}
|
||||
|
||||
|
||||
@@ -247,7 +227,6 @@ Pipeline::shuntNext()
|
||||
}
|
||||
|
||||
setQIDState( q, rc );
|
||||
new FuncTimeout( 0, boost::bind( &Pipeline::shunt, this, q ), this );
|
||||
}
|
||||
|
||||
|
||||
@@ -260,8 +239,7 @@ Pipeline::timeoutShunt( const query_ptr& q )
|
||||
// are we still waiting for a timeout?
|
||||
if ( m_qidsTimeout.contains( q->id() ) )
|
||||
{
|
||||
m_qidsTimeout.remove( q->id() );
|
||||
shunt( q );
|
||||
decQIDState( q );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -278,7 +256,7 @@ Pipeline::shunt( const query_ptr& q )
|
||||
|
||||
if ( r )
|
||||
{
|
||||
qDebug() << "Dispatching to resolver" << r->name() << q->toString() << q->solved() << q->id();
|
||||
tDebug() << "Dispatching to resolver" << r->name() << q->toString() << q->solved() << q->id();
|
||||
|
||||
q->setCurrentResolver( r );
|
||||
r->resolve( q );
|
||||
@@ -291,7 +269,9 @@ Pipeline::shunt( const query_ptr& q )
|
||||
}
|
||||
else
|
||||
{
|
||||
// we get here if we disable a resolver while a query is resolving
|
||||
setQIDState( q, 0 );
|
||||
return;
|
||||
}
|
||||
|
||||
shuntNext();
|
||||
@@ -327,14 +307,24 @@ Pipeline::setQIDState( const Tomahawk::query_ptr& query, int state )
|
||||
{
|
||||
QMutexLocker lock( &m_mut );
|
||||
|
||||
if ( m_qidsTimeout.contains( query->id() ) )
|
||||
m_qidsTimeout.remove( query->id() );
|
||||
|
||||
if ( state > 0 )
|
||||
{
|
||||
m_qidsState.insert( query->id(), state );
|
||||
|
||||
new FuncTimeout( 0, boost::bind( &Pipeline::shunt, this, query ), this );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_qidsState.remove( query->id() );
|
||||
// qDebug() << "Queries running:" << m_qidsState.count();
|
||||
query->onResolvingFinished();
|
||||
|
||||
if ( !m_queries_temporary.contains( query ) )
|
||||
m_qids.remove( query->id() );
|
||||
|
||||
new FuncTimeout( 0, boost::bind( &Pipeline::shuntNext, this ), this );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -358,22 +348,17 @@ Pipeline::incQIDState( const Tomahawk::query_ptr& query )
|
||||
int
|
||||
Pipeline::decQIDState( const Tomahawk::query_ptr& query )
|
||||
{
|
||||
QMutexLocker lock( &m_mut );
|
||||
|
||||
if ( !m_qidsState.contains( query->id() ) )
|
||||
return 0;
|
||||
|
||||
int state = m_qidsState.value( query->id() ) - 1;
|
||||
if ( state )
|
||||
int state = 0;
|
||||
{
|
||||
m_qidsState.insert( query->id(), state );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_qidsState.remove( query->id() );
|
||||
// qDebug() << "Queries running:" << m_qidsState.count();
|
||||
QMutexLocker lock( &m_mut );
|
||||
|
||||
if ( !m_qidsState.contains( query->id() ) )
|
||||
return 0;
|
||||
|
||||
state = m_qidsState.value( query->id() ) - 1;
|
||||
}
|
||||
|
||||
setQIDState( query, state );
|
||||
return state;
|
||||
}
|
||||
|
||||
|
@@ -398,12 +398,6 @@ Playlist::setNewRevision( const QString& rev,
|
||||
QList<plentry_ptr> entries;
|
||||
foreach( const QString& id, neworderedguids )
|
||||
{
|
||||
/* qDebug() << "id:" << id;
|
||||
qDebug() << "newordered:" << neworderedguids.count() << neworderedguids;
|
||||
qDebug() << "entriesmap:" << entriesmap.count() << entriesmap;
|
||||
qDebug() << "addedmap:" << addedmap.count() << addedmap;
|
||||
qDebug() << "m_entries" << m_entries; */
|
||||
|
||||
if( entriesmap.contains( id ) )
|
||||
{
|
||||
entries.append( entriesmap.value( id ) );
|
||||
@@ -416,6 +410,13 @@ Playlist::setNewRevision( const QString& rev,
|
||||
}
|
||||
else
|
||||
{
|
||||
/* qDebug() << "id:" << id;
|
||||
* qDebug() << "newordered:" << neworderedguids.count() << neworderedguids;
|
||||
* qDebug() << "entriesmap:" << entriesmap.count() << entriesmap;
|
||||
* qDebug() << "addedmap:" << addedmap.count() << addedmap;
|
||||
* qDebug() << "m_entries" << m_entries; */
|
||||
|
||||
tLog() << "Playlist error for playlist with guid" << guid() << "from source" << author()->friendlyName();
|
||||
Q_ASSERT( false ); // XXX
|
||||
}
|
||||
}
|
||||
|
@@ -35,6 +35,7 @@ using namespace Tomahawk;
|
||||
AlbumModel::AlbumModel( QObject* parent )
|
||||
: QAbstractItemModel( parent )
|
||||
, m_rootItem( new AlbumItem( 0, this ) )
|
||||
, m_overwriteOnAdd( false )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
|
||||
@@ -159,6 +160,7 @@ AlbumModel::headerData( int section, Qt::Orientation orientation, int role ) con
|
||||
Qt::ItemFlags
|
||||
AlbumModel::flags( const QModelIndex& index ) const
|
||||
{
|
||||
qDebug() << "asking for flags for index" << index;
|
||||
Qt::ItemFlags defaultFlags = QAbstractItemModel::flags( index );
|
||||
|
||||
if ( index.isValid() && index.column() == 0 )
|
||||
@@ -195,12 +197,13 @@ AlbumModel::mimeData( const QModelIndexList &indexes ) const
|
||||
if ( item )
|
||||
{
|
||||
const album_ptr& album = item->album();
|
||||
queryStream << qlonglong( &album );
|
||||
queryStream << album->artist()->name();
|
||||
queryStream << album->name();
|
||||
}
|
||||
}
|
||||
|
||||
QMimeData* mimeData = new QMimeData();
|
||||
mimeData->setData( "application/tomahawk.query.list", queryData );
|
||||
mimeData->setData( "application/tomahawk.metadata.album", queryData );
|
||||
|
||||
return mimeData;
|
||||
}
|
||||
@@ -235,13 +238,14 @@ AlbumModel::removeIndexes( const QList<QModelIndex>& indexes )
|
||||
|
||||
|
||||
void
|
||||
AlbumModel::addCollection( const collection_ptr& collection )
|
||||
AlbumModel::addCollection( const collection_ptr& collection, bool overwrite )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << collection->name()
|
||||
<< collection->source()->id()
|
||||
<< collection->source()->userName();
|
||||
|
||||
DatabaseCommand_AllAlbums* cmd = new DatabaseCommand_AllAlbums( collection );
|
||||
m_overwriteOnAdd = overwrite;
|
||||
|
||||
connect( cmd, SIGNAL( albums( QList<Tomahawk::album_ptr>, QVariant ) ),
|
||||
SLOT( addAlbums( QList<Tomahawk::album_ptr> ) ) );
|
||||
@@ -253,7 +257,7 @@ AlbumModel::addCollection( const collection_ptr& collection )
|
||||
|
||||
|
||||
void
|
||||
AlbumModel::addFilteredCollection( const collection_ptr& collection, unsigned int amount, DatabaseCommand_AllAlbums::SortOrder order )
|
||||
AlbumModel::addFilteredCollection( const collection_ptr& collection, unsigned int amount, DatabaseCommand_AllAlbums::SortOrder order, bool overwrite )
|
||||
{
|
||||
/* qDebug() << Q_FUNC_INFO << collection->name()
|
||||
<< collection->source()->id()
|
||||
@@ -264,6 +268,7 @@ AlbumModel::addFilteredCollection( const collection_ptr& collection, unsigned in
|
||||
cmd->setLimit( amount );
|
||||
cmd->setSortOrder( order );
|
||||
cmd->setSortDescending( true );
|
||||
m_overwriteOnAdd = overwrite;
|
||||
|
||||
connect( cmd, SIGNAL( albums( QList<Tomahawk::album_ptr>, QVariant ) ),
|
||||
SLOT( addAlbums( QList<Tomahawk::album_ptr> ) ) );
|
||||
@@ -283,6 +288,9 @@ AlbumModel::addAlbums( const QList<Tomahawk::album_ptr>& albums )
|
||||
if ( !albums.count() )
|
||||
return;
|
||||
|
||||
if ( m_overwriteOnAdd )
|
||||
clear();
|
||||
|
||||
int c = rowCount( QModelIndex() );
|
||||
QPair< int, int > crows;
|
||||
crows.first = c;
|
||||
|
@@ -63,8 +63,8 @@ public:
|
||||
virtual QStringList mimeTypes() const;
|
||||
virtual Qt::ItemFlags flags( const QModelIndex& index ) const;
|
||||
|
||||
void addCollection( const Tomahawk::collection_ptr& collection );
|
||||
void addFilteredCollection( const Tomahawk::collection_ptr& collection, unsigned int amount, DatabaseCommand_AllAlbums::SortOrder order );
|
||||
void addCollection( const Tomahawk::collection_ptr& collection, bool overwrite = false );
|
||||
void addFilteredCollection( const Tomahawk::collection_ptr& collection, unsigned int amount, DatabaseCommand_AllAlbums::SortOrder order, bool overwrite = false );
|
||||
|
||||
void clear();
|
||||
|
||||
@@ -109,6 +109,7 @@ private:
|
||||
|
||||
QString m_title;
|
||||
QString m_description;
|
||||
bool m_overwriteOnAdd;
|
||||
};
|
||||
|
||||
#endif // ALBUMMODEL_H
|
||||
|
@@ -188,27 +188,6 @@ AlbumView::onScrollTimeout()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AlbumView::dragEnterEvent( QDragEnterEvent* event )
|
||||
{
|
||||
QListView::dragEnterEvent( event );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AlbumView::dragMoveEvent( QDragMoveEvent* event )
|
||||
{
|
||||
QListView::dragMoveEvent( event );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AlbumView::dropEvent( QDropEvent* event )
|
||||
{
|
||||
QListView::dropEvent( event );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AlbumView::paintEvent( QPaintEvent* event )
|
||||
{
|
||||
@@ -227,14 +206,30 @@ AlbumView::onFilterChanged( const QString& )
|
||||
void
|
||||
AlbumView::startDrag( Qt::DropActions supportedActions )
|
||||
{
|
||||
Q_UNUSED( supportedActions );
|
||||
}
|
||||
QList<QPersistentModelIndex> pindexes;
|
||||
QModelIndexList indexes;
|
||||
foreach( const QModelIndex& idx, selectedIndexes() )
|
||||
{
|
||||
if ( ( m_proxyModel->flags( idx ) & Qt::ItemIsDragEnabled ) )
|
||||
{
|
||||
indexes << idx;
|
||||
pindexes << idx;
|
||||
}
|
||||
}
|
||||
|
||||
if ( indexes.count() == 0 )
|
||||
return;
|
||||
|
||||
// Inspired from dolphin's draganddrophelper.cpp
|
||||
QPixmap
|
||||
AlbumView::createDragPixmap( int itemCount ) const
|
||||
{
|
||||
Q_UNUSED( itemCount );
|
||||
return QPixmap();
|
||||
qDebug() << "Dragging" << indexes.count() << "indexes";
|
||||
QMimeData* data = m_proxyModel->mimeData( indexes );
|
||||
if ( !data )
|
||||
return;
|
||||
|
||||
QDrag* drag = new QDrag( this );
|
||||
drag->setMimeData( data );
|
||||
const QPixmap p = TomahawkUtils::createDragPixmap( indexes.count() );
|
||||
drag->setPixmap( p );
|
||||
drag->setHotSpot( QPoint( -20, -20 ) );
|
||||
|
||||
Qt::DropAction action = drag->exec( supportedActions, Qt::CopyAction );
|
||||
}
|
||||
|
@@ -60,9 +60,6 @@ public slots:
|
||||
|
||||
protected:
|
||||
virtual void startDrag( Qt::DropActions supportedActions );
|
||||
virtual void dragEnterEvent( QDragEnterEvent* event );
|
||||
virtual void dragMoveEvent( QDragMoveEvent* event );
|
||||
virtual void dropEvent( QDropEvent* event );
|
||||
|
||||
void paintEvent( QPaintEvent* event );
|
||||
|
||||
@@ -73,8 +70,6 @@ private slots:
|
||||
void onScrollTimeout();
|
||||
|
||||
private:
|
||||
QPixmap createDragPixmap( int itemCount ) const;
|
||||
|
||||
AlbumModel* m_model;
|
||||
AlbumProxyModel* m_proxyModel;
|
||||
// PlaylistItemDelegate* m_delegate;
|
||||
|
@@ -412,7 +412,7 @@ query_ptr
|
||||
EchonestGenerator::queryFromSong( const Echonest::Song& song )
|
||||
{
|
||||
// track[ "album" ] = song.release(); // TODO should we include it? can be quite specific
|
||||
return Query::get( song.artistName(), song.title(), QString(), uuid() );
|
||||
return Query::get( song.artistName(), song.title(), QString(), uuid(), false );
|
||||
}
|
||||
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
@@ -21,31 +21,33 @@
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
#include "dllmacro.h"
|
||||
|
||||
class QMovie;
|
||||
class QTimeLine;
|
||||
/**
|
||||
* A small widget that displays an animated loading spinner
|
||||
*/
|
||||
class LoadingSpinner : public QWidget {
|
||||
class DLLEXPORT LoadingSpinner : public QWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
LoadingSpinner( QWidget* parent );
|
||||
virtual ~LoadingSpinner();
|
||||
|
||||
|
||||
virtual QSize sizeHint() const;
|
||||
virtual void paintEvent( QPaintEvent* );
|
||||
virtual void resizeEvent( QResizeEvent* );
|
||||
|
||||
public slots:
|
||||
|
||||
public slots:
|
||||
void fadeIn();
|
||||
void fadeOut();
|
||||
|
||||
|
||||
private slots:
|
||||
void hideFinished();
|
||||
|
||||
|
||||
private:
|
||||
void reposition();
|
||||
|
||||
|
||||
QTimeLine* m_showHide;
|
||||
QMovie* m_anim;
|
||||
};
|
||||
|
@@ -27,7 +27,7 @@
|
||||
#include "database/databasecommand_playbackhistory.h"
|
||||
#include "dynamic/GeneratorInterface.h"
|
||||
#include "utils/logger.h"
|
||||
#include "globalactionmanager.h"
|
||||
#include "dropjob.h"
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
@@ -358,14 +358,15 @@ PlaylistModel::dropMimeData( const QMimeData* data, Qt::DropAction action, int r
|
||||
if ( action == Qt::IgnoreAction || isReadOnly() )
|
||||
return true;
|
||||
|
||||
if ( !GlobalActionManager::instance()->acceptsMimeData( data ) )
|
||||
if ( !DropJob::acceptsMimeData( data ) )
|
||||
return false;
|
||||
|
||||
m_dropStorage.row = row;
|
||||
m_dropStorage.parent = QPersistentModelIndex( parent );
|
||||
m_dropStorage.action = action;
|
||||
connect( GlobalActionManager::instance(), SIGNAL( tracks( QList< Tomahawk::query_ptr > ) ), this, SLOT( parsedDroppedTracks( QList< Tomahawk::query_ptr > ) ) );
|
||||
GlobalActionManager::instance()->tracksFromMimeData( data );
|
||||
DropJob *dj = new DropJob();
|
||||
connect( dj, SIGNAL( tracks( QList< Tomahawk::query_ptr > ) ), this, SLOT( parsedDroppedTracks( QList< Tomahawk::query_ptr > ) ) );
|
||||
dj->tracksFromMimeData( data );
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -377,8 +378,6 @@ PlaylistModel::parsedDroppedTracks( QList< query_ptr > tracks )
|
||||
if ( m_dropStorage.row == -10 ) // nope
|
||||
return;
|
||||
|
||||
disconnect( GlobalActionManager::instance(), SIGNAL( tracks( QList< Tomahawk::query_ptr > ) ), this, SLOT( parsedDroppedTracks( QList< Tomahawk::query_ptr > ) ) );
|
||||
|
||||
int beginRow;
|
||||
if ( m_dropStorage.row != -1 )
|
||||
beginRow = m_dropStorage.row;
|
||||
|
@@ -62,8 +62,10 @@ PlaylistView::setPlaylistModel( PlaylistModel* model )
|
||||
TrackView::setTrackModel( m_model );
|
||||
setColumnHidden( TrackModel::Age, true ); // Hide age column per default
|
||||
|
||||
if ( !m_model->playlist().isNull() )
|
||||
if ( guid().isEmpty() && !m_model->playlist().isNull() )
|
||||
{
|
||||
setGuid( QString( "playlistview/%1/%2" ).arg( m_model->columnCount() ).arg( m_model->playlist()->guid() ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
setGuid( QString( "playlistview/%1" ).arg( m_model->columnCount() ) );
|
||||
|
@@ -110,6 +110,7 @@ void SearchButton::paintEvent(QPaintEvent *event)
|
||||
if (m_cache.isNull())
|
||||
m_cache = generateSearchImage(m_showMenuTriangle);
|
||||
QPainter painter(this);
|
||||
painter.setRenderHint(QPainter::SmoothPixmapTransform);
|
||||
painter.drawImage(QPoint(0, 0), m_cache);
|
||||
}
|
||||
|
||||
|
@@ -71,11 +71,11 @@ TrackHeader::visibleSectionCount() const
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
bool
|
||||
TrackHeader::checkState()
|
||||
{
|
||||
if ( !count() || m_init )
|
||||
return;
|
||||
return false;
|
||||
|
||||
QByteArray state = TomahawkSettings::instance()->playlistColumnSizes( m_parent->guid() );
|
||||
if ( !state.isEmpty() )
|
||||
@@ -102,6 +102,7 @@ TrackHeader::checkState()
|
||||
}
|
||||
|
||||
m_init = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
@@ -40,7 +40,7 @@ public:
|
||||
|
||||
public slots:
|
||||
void toggleVisibility( int index );
|
||||
void checkState();
|
||||
bool checkState();
|
||||
|
||||
protected:
|
||||
void contextMenuEvent( QContextMenuEvent* e );
|
||||
|
@@ -177,7 +177,7 @@ Tomahawk::result_ptr
|
||||
TrackProxyModel::currentItem() const
|
||||
{
|
||||
TrackModelItem* item = itemFromIndex( mapToSource( currentIndex() ) );
|
||||
if ( item && item->query()->playable() )
|
||||
if ( item && !item->query().isNull() && item->query()->playable() )
|
||||
return item->query()->results().at( 0 );
|
||||
return Tomahawk::result_ptr();
|
||||
}
|
||||
@@ -318,8 +318,8 @@ TrackProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right ) c
|
||||
unsigned int albumpos1 = 0, albumpos2 = 0;
|
||||
unsigned int bitrate1 = 0, bitrate2 = 0;
|
||||
unsigned int mtime1 = 0, mtime2 = 0;
|
||||
unsigned int id1 = 0, id2 = 0;
|
||||
unsigned int size1 = 0, size2 = 0;
|
||||
qint64 id1 = 0, id2 = 0;
|
||||
|
||||
if ( q1->numResults() )
|
||||
{
|
||||
@@ -346,6 +346,13 @@ TrackProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right ) c
|
||||
size2 = r->size();
|
||||
}
|
||||
|
||||
// This makes it a stable sorter and prevents items from randomly jumping about.
|
||||
if ( id1 == id2 )
|
||||
{
|
||||
id1 = (qint64)&q1;
|
||||
id2 = (qint64)&q2;
|
||||
}
|
||||
|
||||
if ( left.column() == TrackModel::Artist ) // sort by artist
|
||||
{
|
||||
if ( artist1 == artist2 )
|
||||
@@ -396,6 +403,11 @@ TrackProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right ) c
|
||||
|
||||
return size1 < size2;
|
||||
}
|
||||
return QString::localeAwareCompare( sourceModel()->data( left ).toString(),
|
||||
sourceModel()->data( right ).toString() ) < 0;
|
||||
|
||||
const QString& lefts = sourceModel()->data( left ).toString();
|
||||
const QString& rights = sourceModel()->data( right ).toString();
|
||||
if ( lefts == rights )
|
||||
return id1 < id2;
|
||||
|
||||
return QString::localeAwareCompare( lefts, rights ) < 0;
|
||||
}
|
||||
|
@@ -33,7 +33,7 @@
|
||||
#include "dynamic/widgets/LoadingSpinner.h"
|
||||
#include "utils/tomahawkutils.h"
|
||||
#include "utils/logger.h"
|
||||
#include <globalactionmanager.h>
|
||||
#include "dropjob.h"
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
@@ -62,8 +62,7 @@ TrackView::TrackView( QWidget* parent )
|
||||
setVerticalScrollMode( QAbstractItemView::ScrollPerPixel );
|
||||
setRootIsDecorated( false );
|
||||
setUniformRowHeights( true );
|
||||
setMinimumWidth( 300 );
|
||||
// setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOn );
|
||||
setMinimumWidth( 200 );
|
||||
|
||||
setHeader( m_header );
|
||||
setSortingEnabled( true );
|
||||
@@ -204,7 +203,15 @@ void
|
||||
TrackView::resizeEvent( QResizeEvent* event )
|
||||
{
|
||||
QTreeView::resizeEvent( event );
|
||||
m_header->checkState();
|
||||
|
||||
int sortSection = m_header->sortIndicatorSection();
|
||||
Qt::SortOrder sortOrder = m_header->sortIndicatorOrder();
|
||||
|
||||
if ( m_header->checkState() && sortSection >= 0 )
|
||||
{
|
||||
// restoreState keeps overwriting our previous sort-order
|
||||
sortByColumn( sortSection, sortOrder );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -214,7 +221,7 @@ TrackView::dragEnterEvent( QDragEnterEvent* event )
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
QTreeView::dragEnterEvent( event );
|
||||
|
||||
if ( GlobalActionManager::instance()->acceptsMimeData( event->mimeData() ) )
|
||||
if ( DropJob::acceptsMimeData( event->mimeData() ) )
|
||||
{
|
||||
m_dragging = true;
|
||||
m_dropRect = QRect();
|
||||
@@ -236,7 +243,7 @@ TrackView::dragMoveEvent( QDragMoveEvent* event )
|
||||
return;
|
||||
}
|
||||
|
||||
if ( GlobalActionManager::instance()->acceptsMimeData( event->mimeData() ) )
|
||||
if ( DropJob::acceptsMimeData( event->mimeData() ) )
|
||||
{
|
||||
setDirtyRegion( m_dropRect );
|
||||
const QPoint pos = event->pos();
|
||||
@@ -278,7 +285,7 @@ TrackView::dropEvent( QDropEvent* event )
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( GlobalActionManager::instance()->acceptsMimeData( event->mimeData() ) )
|
||||
if ( DropJob::acceptsMimeData( event->mimeData() ) )
|
||||
{
|
||||
const QPoint pos = event->pos();
|
||||
const QModelIndex index = indexAt( pos );
|
||||
|
@@ -293,6 +293,8 @@ TreeModel::flags( const QModelIndex& index ) const
|
||||
TreeModelItem* item = itemFromIndex( index );
|
||||
if ( item && !item->result().isNull() )
|
||||
return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags;
|
||||
if ( item && ( !item->album().isNull() || !item->artist().isNull() ) )
|
||||
return Qt::ItemIsDragEnabled | defaultFlags;
|
||||
}
|
||||
|
||||
return defaultFlags;
|
||||
@@ -303,7 +305,7 @@ QStringList
|
||||
TreeModel::mimeTypes() const
|
||||
{
|
||||
QStringList types;
|
||||
types << "application/tomahawk.result.list";
|
||||
types << "application/tomahawk.mixed";
|
||||
return types;
|
||||
}
|
||||
|
||||
@@ -316,23 +318,124 @@ TreeModel::mimeData( const QModelIndexList &indexes ) const
|
||||
QByteArray resultData;
|
||||
QDataStream resultStream( &resultData, QIODevice::WriteOnly );
|
||||
|
||||
foreach ( const QModelIndex& i, indexes )
|
||||
// lets try with artist only
|
||||
bool fail = false;
|
||||
foreach ( const QModelIndex& i, indexes)
|
||||
{
|
||||
if ( i.column() > 0 )
|
||||
if ( i.column() > 0 || indexes.contains( i.parent() ) )
|
||||
continue;
|
||||
|
||||
QModelIndex idx = index( i.row(), 0, i.parent() );
|
||||
TreeModelItem* item = itemFromIndex( idx );
|
||||
if ( item && !item->result().isNull() )
|
||||
TreeModelItem* item = itemFromIndex( i );
|
||||
if ( !item )
|
||||
continue;
|
||||
|
||||
if ( !item->artist().isNull() )
|
||||
{
|
||||
const artist_ptr& artist = item->artist();
|
||||
resultStream << artist->name();
|
||||
}
|
||||
else
|
||||
{
|
||||
fail = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( !fail )
|
||||
{
|
||||
QMimeData* mimeData = new QMimeData();
|
||||
mimeData->setData( "application/tomahawk.metadata.artist", resultData );
|
||||
return mimeData;
|
||||
}
|
||||
|
||||
// lets try with album only
|
||||
fail = false;
|
||||
foreach ( const QModelIndex& i, indexes)
|
||||
{
|
||||
if ( i.column() > 0 || indexes.contains( i.parent() ) )
|
||||
continue;
|
||||
|
||||
TreeModelItem* item = itemFromIndex( i );
|
||||
if ( !item )
|
||||
continue;
|
||||
|
||||
if ( !item->album().isNull() )
|
||||
{
|
||||
const album_ptr& album = item->album();
|
||||
resultStream << album->artist()->name();
|
||||
resultStream << album->name();
|
||||
}
|
||||
else
|
||||
{
|
||||
fail = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( !fail )
|
||||
{
|
||||
QMimeData* mimeData = new QMimeData();
|
||||
mimeData->setData( "application/tomahawk.metadata.album", resultData );
|
||||
return mimeData;
|
||||
}
|
||||
|
||||
|
||||
// lets try with tracks only
|
||||
fail = false;
|
||||
foreach ( const QModelIndex& i, indexes)
|
||||
{
|
||||
if ( i.column() > 0 || indexes.contains( i.parent() ) )
|
||||
continue;
|
||||
|
||||
TreeModelItem* item = itemFromIndex( i );
|
||||
if ( !item )
|
||||
continue;
|
||||
|
||||
if ( !item->result().isNull() )
|
||||
{
|
||||
const result_ptr& result = item->result();
|
||||
resultStream << qlonglong( &result );
|
||||
}
|
||||
else
|
||||
{
|
||||
fail = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( !fail )
|
||||
{
|
||||
QMimeData* mimeData = new QMimeData();
|
||||
mimeData->setData( "application/tomahawk.result.list", resultData );
|
||||
return mimeData;
|
||||
}
|
||||
|
||||
// Ok... we have to use mixed
|
||||
foreach ( const QModelIndex& i, indexes )
|
||||
{
|
||||
if ( i.column() > 0 || indexes.contains( i.parent() ) )
|
||||
continue;
|
||||
|
||||
TreeModelItem* item = itemFromIndex( i );
|
||||
if ( !item )
|
||||
continue;
|
||||
|
||||
if ( !item->artist().isNull() )
|
||||
{
|
||||
const artist_ptr& artist = item->artist();
|
||||
resultStream << QString( "application/tomahawk.metadata.artist" ) << artist->name();
|
||||
}
|
||||
else if ( !item->album().isNull() )
|
||||
{
|
||||
const album_ptr& album = item->album();
|
||||
resultStream << QString( "application/tomahawk.metadata.album" ) << album->artist()->name() << album->name();
|
||||
}
|
||||
else if ( !item->result().isNull() )
|
||||
{
|
||||
const result_ptr& result = item->result();
|
||||
resultStream << QString( "application/tomahawk.result.list" ) << qlonglong( &result );
|
||||
}
|
||||
}
|
||||
|
||||
QMimeData* mimeData = new QMimeData();
|
||||
mimeData->setData( "application/tomahawk.result.list", resultData );
|
||||
|
||||
mimeData->setData( "application/tomahawk.mixed", resultData );
|
||||
return mimeData;
|
||||
}
|
||||
|
||||
@@ -513,6 +616,8 @@ void
|
||||
TreeModel::onAlbumsAdded( const QList<Tomahawk::album_ptr>& albums, const QVariant& data )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << albums.count() << data.toInt();
|
||||
|
||||
emit loadingFinished();
|
||||
if ( !albums.count() )
|
||||
return;
|
||||
|
||||
@@ -555,8 +660,6 @@ TreeModel::onAlbumsAdded( const QList<Tomahawk::album_ptr>& albums, const QVaria
|
||||
emit endInsertRows();
|
||||
else
|
||||
emit dataChanged( albumitem->index, albumitem->index.sibling( albumitem->index.row(), columnCount( QModelIndex() ) - 1 ) );
|
||||
|
||||
emit loadingFinished();
|
||||
}
|
||||
|
||||
|
||||
@@ -564,6 +667,8 @@ void
|
||||
TreeModel::onTracksAdded( const QList<Tomahawk::query_ptr>& tracks, const QVariant& data )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << tracks.count();
|
||||
|
||||
emit loadingFinished();
|
||||
if ( !tracks.count() )
|
||||
return;
|
||||
|
||||
@@ -597,8 +702,6 @@ TreeModel::onTracksAdded( const QList<Tomahawk::query_ptr>& tracks, const QVaria
|
||||
emit endInsertRows();
|
||||
|
||||
emit dataChanged( item->index.sibling( 0, 0 ), item->index.sibling( item->index.row(), columnCount( QModelIndex() ) - 1 ) );
|
||||
|
||||
emit loadingFinished();
|
||||
}
|
||||
|
||||
|
||||
|
@@ -81,8 +81,11 @@ TreeProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent
|
||||
QList< Tomahawk::result_ptr > rl = m_cache.values( sourceParent );
|
||||
foreach ( const Tomahawk::result_ptr& result, rl )
|
||||
{
|
||||
if ( result->track() == pi->result()->track() )
|
||||
if ( result->track() == pi->result()->track() &&
|
||||
( result->albumpos() == pi->result()->albumpos() || result->albumpos() == 0 ) )
|
||||
{
|
||||
return ( result.data() == pi->result().data() );
|
||||
}
|
||||
}
|
||||
|
||||
for ( int i = 0; i < sourceModel()->rowCount( sourceParent ); i++ )
|
||||
@@ -91,7 +94,9 @@ TreeProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent
|
||||
continue;
|
||||
|
||||
TreeModelItem* ti = sourceModel()->itemFromIndex( sourceModel()->index( i, 0, sourceParent ) );
|
||||
if ( ti->result()->track() == pi->result()->track() )
|
||||
|
||||
if ( ti->result()->track() == pi->result()->track() &&
|
||||
( ti->result()->albumpos() == pi->result()->albumpos() || ti->result()->albumpos() == 0 ) )
|
||||
{
|
||||
if ( !pi->result()->isOnline() && ti->result()->isOnline() )
|
||||
return false;
|
||||
@@ -133,13 +138,19 @@ TreeProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right ) co
|
||||
if ( !p2 )
|
||||
return false;
|
||||
|
||||
const QString& lefts = textForItem( p1 );
|
||||
const QString& rights = textForItem( p2 );
|
||||
|
||||
if ( !p1->result().isNull() )
|
||||
{
|
||||
if ( p1->result()->albumpos() != p2->result()->albumpos() )
|
||||
return p1->result()->albumpos() < p2->result()->albumpos();
|
||||
|
||||
if ( lefts == rights )
|
||||
return (qint64)&p1 < (qint64)&p2;
|
||||
}
|
||||
|
||||
return QString::localeAwareCompare( textForItem( p1 ), textForItem( p2 ) ) < 0;
|
||||
return QString::localeAwareCompare( lefts, rights ) < 0;
|
||||
}
|
||||
|
||||
|
||||
|
@@ -176,6 +176,8 @@ Query::onResolvingFinished()
|
||||
if ( !m_resolveFinished )
|
||||
{
|
||||
m_resolveFinished = true;
|
||||
m_resolvers.clear();
|
||||
|
||||
emit resolvingFinished( m_solved );
|
||||
}
|
||||
}
|
||||
|
@@ -18,15 +18,17 @@
|
||||
|
||||
#include "tomahawkutils.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QColor>
|
||||
#include <QDateTime>
|
||||
#include <QDir>
|
||||
#include <QLayout>
|
||||
#include <QPainter>
|
||||
#include <QPixmap>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkProxy>
|
||||
#include "headlesscheck.h"
|
||||
#include <QtCore/QCoreApplication>
|
||||
|
||||
#include <QtGui/QColor>
|
||||
#include <QtCore/QDateTime>
|
||||
#include <QtCore/QDir>
|
||||
#include <QtGui/QLayout>
|
||||
#include <QtGui/QPainter>
|
||||
#include <QtGui/QPixmap>
|
||||
#include <QtNetwork/QNetworkAccessManager>
|
||||
#include <QtNetwork/QNetworkProxy>
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
@@ -38,6 +40,21 @@
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
#ifndef TOMAHAWK_HEADLESS
|
||||
#include <QtGui/QApplication>
|
||||
#include <QtGui/QWidget>
|
||||
|
||||
#ifdef Q_WS_X11
|
||||
#include <QtGui/QX11Info>
|
||||
#include <libqnetwm/netwm.h>
|
||||
#endif
|
||||
|
||||
#ifdef Q_WS_WIN
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <tomahawksettings.h>
|
||||
#include "utils/logger.h"
|
||||
#include "config.h"
|
||||
@@ -506,13 +523,90 @@ setNam( QNetworkAccessManager* nam )
|
||||
}
|
||||
|
||||
|
||||
#ifndef TOMAHAWK_HEADLESS
|
||||
|
||||
QWidget*
|
||||
tomahawkWindow()
|
||||
{
|
||||
QWidgetList widgetList = qApp->topLevelWidgets();
|
||||
int i = 0;
|
||||
while( i < widgetList.count() && widgetList.at( i )->objectName() != "TH_Main_Window" )
|
||||
i++;
|
||||
|
||||
if ( i == widgetList.count() )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << "could not find main Tomahawk mainwindow";
|
||||
Q_ASSERT( false );
|
||||
return 0;
|
||||
}
|
||||
|
||||
QWidget *widget = widgetList.at( i );
|
||||
return widget;
|
||||
}
|
||||
|
||||
|
||||
#ifndef Q_OS_MAC
|
||||
void
|
||||
bringToFront()
|
||||
{
|
||||
#if defined(Q_WS_X11)
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
|
||||
QWidget* widget = tomahawkWindow();
|
||||
if ( !widget )
|
||||
return;
|
||||
|
||||
widget->show();
|
||||
widget->activateWindow();
|
||||
widget->raise();
|
||||
|
||||
WId wid = widget->winId();
|
||||
NETWM::init();
|
||||
|
||||
XEvent e;
|
||||
e.xclient.type = ClientMessage;
|
||||
e.xclient.message_type = NETWM::NET_ACTIVE_WINDOW;
|
||||
e.xclient.display = QX11Info::display();
|
||||
e.xclient.window = wid;
|
||||
e.xclient.format = 32;
|
||||
e.xclient.data.l[0] = 2;
|
||||
e.xclient.data.l[1] = QX11Info::appTime();
|
||||
e.xclient.data.l[2] = 0;
|
||||
e.xclient.data.l[3] = 0l;
|
||||
e.xclient.data.l[4] = 0l;
|
||||
|
||||
XSendEvent( QX11Info::display(), RootWindow( QX11Info::display(), DefaultScreen( QX11Info::display() ) ), False, SubstructureRedirectMask | SubstructureNotifyMask, &e );
|
||||
}
|
||||
#elif defined(Q_WS_WIN)
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
|
||||
QWidget* widget = tomahawkWindow();
|
||||
if ( !widget )
|
||||
return;
|
||||
|
||||
widget->show();
|
||||
widget->activateWindow();
|
||||
widget->raise();
|
||||
|
||||
WId wid = widget->winId();
|
||||
|
||||
HWND hwndActiveWin = GetForegroundWindow();
|
||||
int idActive = GetWindowThreadProcessId(hwndActiveWin, NULL);
|
||||
if ( AttachThreadInput(GetCurrentThreadId(), idActive, TRUE) )
|
||||
{
|
||||
SetForegroundWindow( wid );
|
||||
SetFocus( wid );
|
||||
AttachThreadInput(GetCurrentThreadId(), idActive, FALSE);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
QPixmap
|
||||
createAvatarFrame( const QPixmap &avatar )
|
||||
|
@@ -21,11 +21,11 @@
|
||||
|
||||
#include "dllmacro.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QThread>
|
||||
#include <QNetworkProxy>
|
||||
#include <QStringList>
|
||||
#include <QRect>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QThread>
|
||||
#include <QtNetwork/QNetworkProxy>
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtCore/QRect>
|
||||
|
||||
#define RESPATH ":/data/"
|
||||
|
||||
@@ -86,6 +86,7 @@ namespace TomahawkUtils
|
||||
DLLEXPORT void setProxyFactory( TomahawkUtils::NetworkProxyFactory* factory );
|
||||
DLLEXPORT void setNam( QNetworkAccessManager* nam );
|
||||
|
||||
DLLEXPORT QWidget* tomahawkWindow();
|
||||
/// Platform-specific bringing tomahawk mainwindow to front, b/c qt's activate() and such don't seem to work well enough for us
|
||||
DLLEXPORT void bringToFront();
|
||||
|
||||
|
66
src/libtomahawk/widgets/SeekSlider.cpp
Normal file
66
src/libtomahawk/widgets/SeekSlider.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "SeekSlider.h"
|
||||
|
||||
#include <QMouseEvent>
|
||||
|
||||
#include "utils/tomahawkutils.h"
|
||||
#include "utils/logger.h"
|
||||
|
||||
|
||||
SeekSlider::SeekSlider( QWidget* parent )
|
||||
: QSlider( parent )
|
||||
{
|
||||
setFixedHeight( 20 );
|
||||
setStyleSheet( "QSlider::groove::horizontal {"
|
||||
"margin: 5px; border-width: 3px;"
|
||||
"border-image: url(" RESPATH "images/seek-slider-bkg.png) 3 3 3 3 stretch stretch;"
|
||||
"}"
|
||||
|
||||
"QSlider::sub-page:horizontal {"
|
||||
"margin: 5px; border-width: 3px;"
|
||||
"border-image: url(" RESPATH "images/seek-slider-level.png) 3 3 3 3 stretch stretch;"
|
||||
"}"
|
||||
|
||||
"QSlider::handle::horizontal {"
|
||||
"margin-bottom: -7px; margin-top: -7px;"
|
||||
"margin-left: -4px; margin-right: -4px;"
|
||||
"height: 17px; width: 16px;"
|
||||
"background-image: url(" RESPATH "images/seek-and-volume-knob-rest.png);"
|
||||
"background-repeat: no-repeat;"
|
||||
"}" );
|
||||
}
|
||||
|
||||
|
||||
SeekSlider::~SeekSlider()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SeekSlider::mousePressEvent( QMouseEvent* event )
|
||||
{
|
||||
if ( event->button() == Qt::LeftButton )
|
||||
{
|
||||
QMouseEvent eventSwap( QEvent::MouseButtonRelease, event->pos(), event->globalPos(), Qt::MidButton, Qt::MidButton, event->modifiers() );
|
||||
QSlider::mousePressEvent( &eventSwap );
|
||||
}
|
||||
else
|
||||
QSlider::mousePressEvent( event );
|
||||
}
|
38
src/libtomahawk/widgets/SeekSlider.h
Normal file
38
src/libtomahawk/widgets/SeekSlider.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SEEKSLIDER_H
|
||||
#define SEEKSLIDER_H
|
||||
|
||||
#include <QSlider>
|
||||
|
||||
#include "dllmacro.h"
|
||||
|
||||
class DLLEXPORT SeekSlider : public QSlider
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SeekSlider( QWidget* parent = 0 );
|
||||
~SeekSlider();
|
||||
|
||||
protected:
|
||||
void mousePressEvent( QMouseEvent* event );
|
||||
};
|
||||
|
||||
#endif // SEEKSLIDER_H
|
@@ -31,15 +31,13 @@
|
||||
|
||||
#include "widgets/overlaywidget.h"
|
||||
|
||||
static QString s_aiInfoIdentifier = QString( "ArtistInfoWidget" );
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
|
||||
ArtistInfoWidget::ArtistInfoWidget( const Tomahawk::artist_ptr& artist, QWidget* parent )
|
||||
: QWidget( parent )
|
||||
, ui( new Ui::ArtistInfoWidget )
|
||||
, m_artist( artist )
|
||||
, m_infoId( uuid() )
|
||||
{
|
||||
ui->setupUi( this );
|
||||
|
||||
@@ -95,7 +93,7 @@ ArtistInfoWidget::load( const artist_ptr& artist )
|
||||
artistInfo["artist"] = artist->name();
|
||||
|
||||
Tomahawk::InfoSystem::InfoRequestData requestData;
|
||||
requestData.caller = s_aiInfoIdentifier;
|
||||
requestData.caller = m_infoId;
|
||||
requestData.customData = QVariantMap();
|
||||
|
||||
requestData.input = artist->name();
|
||||
@@ -121,7 +119,7 @@ ArtistInfoWidget::load( const artist_ptr& artist )
|
||||
void
|
||||
ArtistInfoWidget::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QVariant output )
|
||||
{
|
||||
if ( requestData.caller != s_aiInfoIdentifier )
|
||||
if ( requestData.caller != m_infoId )
|
||||
{
|
||||
// qDebug() << "Info of wrong type or not with our identifier";
|
||||
return;
|
||||
@@ -139,6 +137,7 @@ ArtistInfoWidget::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestD
|
||||
}
|
||||
}
|
||||
|
||||
qDebug() << "ARTISTINFOWIDGET got infosystem info for:" << m_title << output.value< Tomahawk::InfoSystem::InfoGenericMap >();
|
||||
QVariantMap returnedData = output.value< QVariantMap >();
|
||||
switch ( requestData.type )
|
||||
{
|
||||
|
@@ -102,6 +102,7 @@ private:
|
||||
QString m_title;
|
||||
QString m_description;
|
||||
QString m_longDescription;
|
||||
QString m_infoId;
|
||||
QPixmap m_pixmap;
|
||||
};
|
||||
|
||||
|
@@ -40,6 +40,15 @@
|
||||
<height>192</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="dragEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="dragDropMode">
|
||||
<enum>QAbstractItemView::DragDrop</enum>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
@@ -84,16 +93,16 @@
|
||||
<extends>QLabel</extends>
|
||||
<header location="global">widgets/HeaderLabel.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>PlaylistView</class>
|
||||
<extends>QTreeView</extends>
|
||||
<header>playlist/playlistview.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>AlbumView</class>
|
||||
<extends>QListView</extends>
|
||||
<header>playlist/albumview.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>PlaylistView</class>
|
||||
<extends>QTreeView</extends>
|
||||
<header>playlist/playlistview.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>CollectionView</class>
|
||||
<extends>QTreeView</extends>
|
||||
|
@@ -39,6 +39,7 @@ SearchWidget::SearchWidget( const QString& search, QWidget* parent )
|
||||
{
|
||||
ui->setupUi( this );
|
||||
|
||||
ui->resultsView->setGuid( "searchwidget" );
|
||||
m_resultsModel = new PlaylistModel( ui->resultsView );
|
||||
ui->resultsView->setPlaylistModel( m_resultsModel );
|
||||
ui->resultsView->overlay()->setEnabled( false );
|
||||
@@ -96,7 +97,6 @@ SearchWidget::onResultsFound( const QList<Tomahawk::result_ptr>& results )
|
||||
Tomahawk::query_ptr q = result->toQuery();
|
||||
q->setResolveFinished( true );
|
||||
q->addResults( rl );
|
||||
qDebug() << result->toString();
|
||||
|
||||
m_resultsModel->append( q );
|
||||
}
|
||||
|
@@ -86,7 +86,7 @@ WelcomeWidget::WelcomeWidget( QWidget* parent )
|
||||
|
||||
m_recentAlbumsModel = new AlbumModel( ui->additionsView );
|
||||
ui->additionsView->setAlbumModel( m_recentAlbumsModel );
|
||||
m_recentAlbumsModel->addFilteredCollection( collection_ptr(), 20, DatabaseCommand_AllAlbums::ModificationTime );
|
||||
m_recentAlbumsModel->addFilteredCollection( collection_ptr(), 20, DatabaseCommand_AllAlbums::ModificationTime, true );
|
||||
|
||||
m_timer = new QTimer( this );
|
||||
connect( m_timer, SIGNAL( timeout() ), SLOT( checkQueries() ) );
|
||||
@@ -108,6 +108,14 @@ void
|
||||
WelcomeWidget::updateRecentTracks()
|
||||
{
|
||||
m_tracksModel->loadHistory( Tomahawk::source_ptr(), HISTORY_TRACK_ITEMS );
|
||||
|
||||
connect( SourceList::instance()->getLocal().data(), SIGNAL( stats( QVariantMap ) ), this, SLOT( updateRecentAdditions() ) );
|
||||
}
|
||||
|
||||
void
|
||||
WelcomeWidget::updateRecentAdditions()
|
||||
{
|
||||
m_recentAlbumsModel->addFilteredCollection( collection_ptr(), 20, DatabaseCommand_AllAlbums::ModificationTime, true );
|
||||
}
|
||||
|
||||
|
||||
|
@@ -103,6 +103,7 @@ signals:
|
||||
public slots:
|
||||
void updateRecentTracks();
|
||||
void updatePlaylists();
|
||||
void updateRecentAdditions();
|
||||
|
||||
private slots:
|
||||
void onSourceAdded( const Tomahawk::source_ptr& source );
|
||||
|
@@ -30,7 +30,14 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="AlbumView" name="additionsView"/>
|
||||
<widget class="AlbumView" name="additionsView">
|
||||
<property name="dragEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
@@ -49,7 +56,7 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QWidget" name="">
|
||||
<widget class="QWidget" name="layoutWidget">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="HeaderLabel" name="label_3">
|
||||
@@ -80,16 +87,16 @@
|
||||
<extends>QLabel</extends>
|
||||
<header location="global">widgets/HeaderLabel.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>PlaylistView</class>
|
||||
<extends>QTreeView</extends>
|
||||
<header>playlist/playlistview.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>AlbumView</class>
|
||||
<extends>QListView</extends>
|
||||
<header>playlist/albumview.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>PlaylistView</class>
|
||||
<extends>QTreeView</extends>
|
||||
<header>playlist/playlistview.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>PlaylistWidget</class>
|
||||
<extends>QListWidget</extends>
|
||||
|
@@ -82,7 +82,7 @@ DirLister::scanDir( QDir dir, int depth, DirLister::Mode mode )
|
||||
return;
|
||||
}
|
||||
|
||||
tDebug( LOGVERBOSE ) << "DirLister::scanDir scanning: " << dir.canonicalPath() << " with mode " << mode;
|
||||
tDebug( LOGVERBOSE ) << "DirLister::scanDir scanning:" << dir.canonicalPath() << "with mode" << mode;
|
||||
if( !dir.exists() )
|
||||
{
|
||||
tDebug( LOGVERBOSE ) << "Dir no longer exists, not scanning";
|
||||
@@ -283,14 +283,6 @@ MusicScanner::listerFinished( const QMap<QString, unsigned int>& newmtimes )
|
||||
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>(cmd) );
|
||||
}
|
||||
|
||||
// re-calculate source stats
|
||||
{
|
||||
DatabaseCommand_CollectionStats* cmd = new DatabaseCommand_CollectionStats( SourceList::instance()->getLocal() );
|
||||
connect( cmd, SIGNAL( done( QVariantMap ) ),
|
||||
SourceList::instance()->getLocal().data(), SLOT( setStats( QVariantMap ) ), Qt::QueuedConnection );
|
||||
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>( cmd ) );
|
||||
}
|
||||
|
||||
if ( !m_dirLister.isNull() )
|
||||
{
|
||||
m_dirListerThreadController->quit();;
|
||||
|
@@ -183,7 +183,7 @@ QtScriptResolver::init()
|
||||
}
|
||||
const QByteArray scriptContents = scriptFile.readAll();
|
||||
|
||||
m_engine->mainFrame()->setHtml( "<html><body></body></html>" );
|
||||
m_engine->mainFrame()->setHtml( "<html><body></body></html>", QUrl( "file:///invalid/file/for/security/policy" ) );
|
||||
|
||||
// add c++ part of tomahawk javascript library
|
||||
m_engine->mainFrame()->addToJavaScriptWindowObject( "Tomahawk", m_resolverHelper );
|
||||
|
@@ -109,6 +109,11 @@ ResolversModel::setData( const QModelIndex& index, const QVariant& value, int ro
|
||||
m_enabledResolvers.append( resolver );
|
||||
|
||||
TomahawkApp::instance()->enableScriptResolver( resolver );
|
||||
emit dataChanged( index, index );
|
||||
|
||||
if( Tomahawk::ExternalResolver* res = TomahawkApp::instance()->resolverForPath( resolver ) ) {
|
||||
connect( res, SIGNAL( changed() ), this, SLOT( resolverChanged() ) );
|
||||
}
|
||||
} else if( state == Qt::Unchecked ) {
|
||||
m_enabledResolvers.removeAll( resolver );
|
||||
|
||||
|
@@ -51,6 +51,7 @@
|
||||
|
||||
#include "ui_proxydialog.h"
|
||||
#include "ui_stackedsettingsdialog.h"
|
||||
#include <playlist/dynamic/widgets/LoadingSpinner.h>
|
||||
|
||||
static QString
|
||||
md5( const QByteArray& src )
|
||||
@@ -66,6 +67,7 @@ SettingsDialog::SettingsDialog( QWidget *parent )
|
||||
, m_rejected( false )
|
||||
, m_sipModel( 0 )
|
||||
, m_resolversModel( 0 )
|
||||
, m_sipSpinner( 0 )
|
||||
{
|
||||
ui->setupUi( this );
|
||||
TomahawkSettings* s = TomahawkSettings::instance();
|
||||
@@ -107,6 +109,16 @@ SettingsDialog::SettingsDialog( QWidget *parent )
|
||||
m_sipModel = new SipModel( this );
|
||||
ui->accountsView->setModel( m_sipModel );
|
||||
|
||||
if ( !Servent::instance()->isReady() )
|
||||
{
|
||||
m_sipSpinner = new LoadingSpinner( ui->accountsView );
|
||||
m_sipSpinner->fadeIn();
|
||||
|
||||
ui->addSipButton->setEnabled( false );
|
||||
ui->removeSipButton->setEnabled( false );
|
||||
connect( Servent::instance(), SIGNAL( ready() ), this, SLOT( serventReady() ) );
|
||||
}
|
||||
|
||||
setupSipButtons();
|
||||
|
||||
ui->staticHostName->setText( s->externalHostname() );
|
||||
@@ -228,6 +240,13 @@ SettingsDialog::~SettingsDialog()
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void
|
||||
SettingsDialog::serventReady()
|
||||
{
|
||||
m_sipSpinner->fadeOut();
|
||||
ui->addSipButton->setEnabled( true );
|
||||
ui->removeSipButton->setEnabled( true );
|
||||
}
|
||||
|
||||
void
|
||||
SettingsDialog::createIcons()
|
||||
|
@@ -22,6 +22,7 @@
|
||||
#include <QDialog>
|
||||
#include <QModelIndex>
|
||||
|
||||
class LoadingSpinner;
|
||||
class QListWidgetItem;
|
||||
class Ui_StackedSettingsDialog;
|
||||
class SipPluginFactory;
|
||||
@@ -100,6 +101,7 @@ private slots:
|
||||
void sipCreateConfigClosed( int value );
|
||||
|
||||
void changePage( QListWidgetItem*, QListWidgetItem* );
|
||||
void serventReady();
|
||||
|
||||
private:
|
||||
void createIcons();
|
||||
@@ -112,6 +114,7 @@ private:
|
||||
bool m_rejected;
|
||||
SipModel* m_sipModel;
|
||||
ResolversModel* m_resolversModel;
|
||||
LoadingSpinner* m_sipSpinner;
|
||||
};
|
||||
|
||||
#endif // SETTINGSDIALOG_H
|
||||
|
@@ -1,3 +1,22 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2011, Michael Zanetti <mzanetti@kde.org>
|
||||
* Copyright 2011, Leo Franchi <lfranchi@kde.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "settingslistdelegate.h"
|
||||
#include "utils/logger.h"
|
||||
|
||||
|
@@ -1,3 +1,22 @@
|
||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||
*
|
||||
* Copyright 2011, Michael Zanetti <mzanetti@kde.org>
|
||||
* Copyright 2011, Leo Franchi <lfranchi@kde.org>
|
||||
*
|
||||
* Tomahawk is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Tomahawk is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SETTINGSLISTDELEGATE_H
|
||||
#define SETTINGSLISTDELEGATE_H
|
||||
|
||||
|
@@ -82,8 +82,8 @@ void AvatarManager::onNewPresence(const Jreen::Presence& presence)
|
||||
// qDebug() << presence.from().full() << "vcard: photo already cached no request necessary " << update->photoHash();
|
||||
m_JidsAvatarHashes.insert( update->photoHash(), presence.from().bare() );
|
||||
|
||||
Q_ASSERT(!this->avatar(presence.from().bare()).isNull());
|
||||
emit newAvatar(presence.from().bare());
|
||||
if ( !this->avatar( presence.from().bare() ).isNull() )
|
||||
emit newAvatar(presence.from().bare());
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@@ -20,6 +20,8 @@
|
||||
#include "googlewrapper.h"
|
||||
#include "ui_configwidget.h"
|
||||
|
||||
#include "utils/tomahawkutils.h"
|
||||
|
||||
#include <QtPlugin>
|
||||
#include <QInputDialog>
|
||||
|
||||
@@ -69,9 +71,8 @@ void
|
||||
GoogleWrapper::showAddFriendDialog()
|
||||
{
|
||||
bool ok;
|
||||
QString id = QInputDialog::getText( 0, tr( "Add Friend" ),
|
||||
tr( "Enter Google Address:" ), QLineEdit::Normal,
|
||||
"", &ok );
|
||||
QString id = QInputDialog::getText( TomahawkUtils::tomahawkWindow(), tr( "Add Friend" ),
|
||||
tr( "Enter Google Address:" ), QLineEdit::Normal, "", &ok );
|
||||
if ( !ok )
|
||||
return;
|
||||
|
||||
|
@@ -467,9 +467,8 @@ void
|
||||
JabberPlugin::showAddFriendDialog()
|
||||
{
|
||||
bool ok;
|
||||
QString id = QInputDialog::getText( 0, tr( "Add Friend" ),
|
||||
tr( "Enter Jabber ID:" ), QLineEdit::Normal,
|
||||
"", &ok );
|
||||
QString id = QInputDialog::getText( TomahawkUtils::tomahawkWindow(), tr( "Add Friend" ),
|
||||
tr( "Enter Jabber ID:" ), QLineEdit::Normal, "", &ok );
|
||||
if ( !ok )
|
||||
return;
|
||||
|
||||
@@ -712,7 +711,7 @@ void JabberPlugin::onSubscriptionReceived(const Jreen::RosterItem::Ptr& item, co
|
||||
tr( "Authorize User" ),
|
||||
QString( tr( "Do you want to grant <b>%1</b> access to your Collection?" ) ).arg(presence.from().bare()),
|
||||
QMessageBox::Yes | QMessageBox::No,
|
||||
0
|
||||
TomahawkUtils::tomahawkWindow()
|
||||
);
|
||||
|
||||
// add confirmBox to m_subscriptionConfirmBoxes
|
||||
|
@@ -6,7 +6,7 @@
|
||||
|
||||
|
||||
TomahawkOAuthTwitter::TomahawkOAuthTwitter( QNetworkAccessManager *nam, QObject* parent )
|
||||
: OAuthTwitter( QByteArray( "C4v4Wfa21rfIDck4HMR3A" ), QByteArray( "zXSjU6bjrvg6UVMJX4JufqHyjj3iextY14SR9uBEAo" ), parent )
|
||||
: OAuthTwitter( QByteArray::fromBase64( "QzR2NFdmYTIxcmZJRGNrNEhNUjNB" ), QByteArray::fromBase64( "elhTalU2Ympydmc2VVZNSlg0SnVmcUh5amozaWV4dFkxNFNSOXVCRUFv" ), parent )
|
||||
{
|
||||
setNetworkAccessManager( nam );
|
||||
}
|
||||
|
@@ -59,42 +59,43 @@ TwitterPlugin::TwitterPlugin( const QString& pluginId )
|
||||
, m_isAuthed( false )
|
||||
, m_checkTimer( this )
|
||||
, m_connectTimer( this )
|
||||
, m_dmPollTimer( this )
|
||||
, m_cachedFriendsSinceId( 0 )
|
||||
, m_cachedMentionsSinceId( 0 )
|
||||
, m_cachedDirectMessagesSinceId( 0 )
|
||||
, m_cachedPeers()
|
||||
, m_keyCache()
|
||||
, m_finishedFriends( false )
|
||||
, m_finishedMentions( false )
|
||||
, m_state( Disconnected )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
|
||||
if ( !Database::instance() || Database::instance()->dbid() != twitterSavedDbid() )
|
||||
if ( Database::instance()->dbid() != twitterSavedDbid() )
|
||||
{
|
||||
if ( !twitterSavedDbid().isEmpty() ) //remove eventually (post 0.2), here for migration purposes
|
||||
{
|
||||
setTwitterCachedDirectMessagesSinceId( 0 );
|
||||
setTwitterCachedFriendsSinceId( 0 );
|
||||
setTwitterCachedMentionsSinceId( 0 );
|
||||
setTwitterCachedPeers( QHash< QString, QVariant >() );
|
||||
}
|
||||
setTwitterSavedDbid( Database::instance()->dbid() );
|
||||
setTwitterCachedDirectMessagesSinceId( 0 );
|
||||
setTwitterCachedFriendsSinceId( 0 );
|
||||
setTwitterCachedMentionsSinceId( 0 );
|
||||
setTwitterCachedPeers( QVariantHash() );
|
||||
}
|
||||
|
||||
m_checkTimer.setInterval( 150000 );
|
||||
setTwitterSavedDbid( Database::instance()->dbid() );
|
||||
|
||||
m_checkTimer.setInterval( 180000 );
|
||||
m_checkTimer.setSingleShot( false );
|
||||
connect( &m_checkTimer, SIGNAL( timeout() ), SLOT( checkTimerFired() ) );
|
||||
|
||||
m_connectTimer.setInterval( 150000 );
|
||||
m_dmPollTimer.setInterval( 60000 );
|
||||
m_dmPollTimer.setSingleShot( false );
|
||||
connect( &m_dmPollTimer, SIGNAL( timeout() ), SLOT( pollDirectMessages() ) );
|
||||
|
||||
m_connectTimer.setInterval( 180000 );
|
||||
m_connectTimer.setSingleShot( false );
|
||||
connect( &m_connectTimer, SIGNAL( timeout() ), SLOT( connectTimerFired() ) );
|
||||
|
||||
m_configWidget = QWeakPointer< TwitterConfigWidget >( new TwitterConfigWidget( this, 0 ) );
|
||||
connect( m_configWidget.data(), SIGNAL( twitterAuthed( bool ) ), SLOT( configDialogAuthedSignalSlot( bool ) ) );
|
||||
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TwitterPlugin::configDialogAuthedSignalSlot( bool authed )
|
||||
{
|
||||
@@ -171,10 +172,16 @@ TwitterPlugin::connectPlugin( bool startup )
|
||||
qStableSort( peerlist.begin(), peerlist.end() );
|
||||
foreach( QString screenName, peerlist )
|
||||
{
|
||||
QHash< QString, QVariant > cachedPeer = m_cachedPeers[screenName].toHash();
|
||||
QVariantHash cachedPeer = m_cachedPeers[screenName].toHash();
|
||||
if ( cachedPeer.contains( "onod" ) && cachedPeer["onod"] != Database::instance()->dbid() )
|
||||
{
|
||||
m_cachedPeers.remove( screenName );
|
||||
syncConfig();
|
||||
}
|
||||
foreach( QString prop, cachedPeer.keys() )
|
||||
qDebug() << "TwitterPlugin : " << screenName << ", key " << prop << ", value " << ( cachedPeer[prop].canConvert< QString >() ? cachedPeer[prop].toString() : QString::number( cachedPeer[prop].toInt() ) );
|
||||
QMetaObject::invokeMethod( this, "registerOffer", Q_ARG( QString, screenName ), QGenericArgument( "QHash< QString, QVariant >", (const void*)&cachedPeer ) );
|
||||
|
||||
QMetaObject::invokeMethod( this, "registerOffer", Q_ARG( QString, screenName ), Q_ARG( QVariantHash, cachedPeer ) );
|
||||
}
|
||||
|
||||
if ( twitterOAuthToken().isEmpty() || twitterOAuthTokenSecret().isEmpty() )
|
||||
@@ -222,6 +229,7 @@ TwitterPlugin::disconnectPlugin()
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
m_checkTimer.stop();
|
||||
m_connectTimer.stop();
|
||||
m_dmPollTimer.stop();
|
||||
if( !m_friendsTimeline.isNull() )
|
||||
delete m_friendsTimeline.data();
|
||||
if( !m_mentions.isNull() )
|
||||
@@ -235,6 +243,7 @@ TwitterPlugin::disconnectPlugin()
|
||||
if( !m_twitterAuth.isNull() )
|
||||
delete m_twitterAuth.data();
|
||||
|
||||
syncConfig();
|
||||
m_cachedPeers.empty();
|
||||
m_state = Disconnected;
|
||||
emit stateChanged( m_state );
|
||||
@@ -250,6 +259,7 @@ TwitterPlugin::connectAuthVerifyReply( const QTweetUser &user )
|
||||
m_state = Disconnected;
|
||||
m_connectTimer.stop();
|
||||
m_checkTimer.stop();
|
||||
m_dmPollTimer.stop();
|
||||
emit stateChanged( m_state );
|
||||
}
|
||||
else
|
||||
@@ -274,6 +284,7 @@ TwitterPlugin::connectAuthVerifyReply( const QTweetUser &user )
|
||||
emit stateChanged( m_state );
|
||||
m_connectTimer.start();
|
||||
m_checkTimer.start();
|
||||
m_dmPollTimer.start();
|
||||
QMetaObject::invokeMethod( this, "checkTimerFired", Qt::AutoConnection );
|
||||
QTimer::singleShot( 20000, this, SLOT( connectTimerFired() ) );
|
||||
}
|
||||
@@ -292,6 +303,7 @@ TwitterPlugin::connectAuthVerifyReply( const QTweetUser &user )
|
||||
m_state = Disconnected;
|
||||
m_connectTimer.stop();
|
||||
m_checkTimer.stop();
|
||||
m_dmPollTimer.stop();
|
||||
emit stateChanged( m_state );
|
||||
}
|
||||
}
|
||||
@@ -349,12 +361,13 @@ TwitterPlugin::connectTimerFired()
|
||||
foreach( QString screenName, peerlist )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << " checking peer " << screenName;
|
||||
QHash< QString, QVariant > peerData = m_cachedPeers[screenName].toHash();
|
||||
QVariantHash peerData = m_cachedPeers[screenName].toHash();
|
||||
|
||||
if ( Servent::instance()->connectedToSession( peerData["node"].toString() ) )
|
||||
{
|
||||
peerData["lastseen"] = QDateTime::currentMSecsSinceEpoch();
|
||||
m_cachedPeers[screenName] = peerData;
|
||||
syncConfig();
|
||||
qDebug() << Q_FUNC_INFO << " already connected";
|
||||
continue;
|
||||
}
|
||||
@@ -363,6 +376,7 @@ TwitterPlugin::connectTimerFired()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << " aging peer " << screenName << " out of cache";
|
||||
m_cachedPeers.remove( screenName );
|
||||
syncConfig();
|
||||
m_cachedAvatars.remove( screenName );
|
||||
continue;
|
||||
}
|
||||
@@ -373,7 +387,7 @@ TwitterPlugin::connectTimerFired()
|
||||
continue;
|
||||
}
|
||||
|
||||
QMetaObject::invokeMethod( this, "registerOffer", Q_ARG( QString, screenName ), QGenericArgument( "QHash< QString, QVariant >", (const void*)&peerData ) );
|
||||
QMetaObject::invokeMethod( this, "registerOffer", Q_ARG( QString, screenName ), Q_ARG( QVariantHash, peerData ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -407,21 +421,23 @@ TwitterPlugin::parseGotTomahawk( const QRegExp ®ex, const QString &screenName
|
||||
else
|
||||
qDebug() << "TwitterPlugin parsed node " << node << " out of the tweet";
|
||||
|
||||
if ( screenName == myScreenName && node == Database::instance()->dbid() )
|
||||
if ( node == Database::instance()->dbid() )
|
||||
{
|
||||
qDebug() << "My screen name and my dbid found; ignoring";
|
||||
qDebug() << "My dbid found; ignoring";
|
||||
return;
|
||||
}
|
||||
|
||||
QHash< QString, QVariant > peerData;
|
||||
QVariantHash peerData;
|
||||
if( m_cachedPeers.contains( screenName ) )
|
||||
{
|
||||
peerData = m_cachedPeers[screenName].toHash();
|
||||
//force a re-send of info but no need to re-register
|
||||
peerData["resend"] = QVariant::fromValue< bool >( true );
|
||||
if ( peerData["node"].toString() != node )
|
||||
peerData["rekey"] = QVariant::fromValue< bool >( true );
|
||||
}
|
||||
peerData["node"] = QVariant::fromValue< QString >( node );
|
||||
QMetaObject::invokeMethod( this, "registerOffer", Q_ARG( QString, screenName ), QGenericArgument( "QHash< QString, QVariant >", (const void*)&peerData ) );
|
||||
QMetaObject::invokeMethod( this, "registerOffer", Q_ARG( QString, screenName ), Q_ARG( QVariantHash, peerData ) );
|
||||
}
|
||||
|
||||
void
|
||||
@@ -429,7 +445,6 @@ TwitterPlugin::friendsTimelineStatuses( const QList< QTweetStatus > &statuses )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
QRegExp regex( s_gotTomahawkRegex, Qt::CaseSensitive, QRegExp::RegExp2 );
|
||||
QString myScreenName = twitterScreenName();
|
||||
|
||||
QHash< QString, QTweetStatus > latestHash;
|
||||
foreach ( QTweetStatus status, statuses )
|
||||
@@ -456,9 +471,6 @@ TwitterPlugin::friendsTimelineStatuses( const QList< QTweetStatus > &statuses )
|
||||
}
|
||||
|
||||
setTwitterCachedFriendsSinceId( m_cachedFriendsSinceId );
|
||||
|
||||
m_finishedFriends = true;
|
||||
QMetaObject::invokeMethod( this, "pollDirectMessages", Qt::AutoConnection );
|
||||
}
|
||||
|
||||
void
|
||||
@@ -492,20 +504,11 @@ TwitterPlugin::mentionsStatuses( const QList< QTweetStatus > &statuses )
|
||||
}
|
||||
|
||||
setTwitterCachedMentionsSinceId( m_cachedMentionsSinceId );
|
||||
|
||||
m_finishedMentions = true;
|
||||
QMetaObject::invokeMethod( this, "pollDirectMessages", Qt::AutoConnection );
|
||||
}
|
||||
|
||||
void
|
||||
TwitterPlugin::pollDirectMessages()
|
||||
{
|
||||
if ( !m_finishedMentions || !m_finishedFriends )
|
||||
return;
|
||||
|
||||
m_finishedFriends = false;
|
||||
m_finishedMentions = false;
|
||||
|
||||
if ( !isValid() )
|
||||
return;
|
||||
|
||||
@@ -580,9 +583,9 @@ TwitterPlugin::directMessages( const QList< QTweetDMStatus > &messages )
|
||||
qDebug() << "TwitterPlugin found a peerstart message from " << status.senderScreenName() << " with host " << host << " and port " << port << " and pkey " << pkey << " and node " << splitNode[0] << " destined for node " << splitNode[1];
|
||||
|
||||
|
||||
QHash< QString, QVariant > peerData = ( m_cachedPeers.contains( status.senderScreenName() ) ) ?
|
||||
QVariantHash peerData = ( m_cachedPeers.contains( status.senderScreenName() ) ) ?
|
||||
m_cachedPeers[status.senderScreenName()].toHash() :
|
||||
QHash< QString, QVariant >();
|
||||
QVariantHash();
|
||||
|
||||
peerData["host"] = QVariant::fromValue< QString >( host );
|
||||
peerData["port"] = QVariant::fromValue< int >( port );
|
||||
@@ -590,7 +593,7 @@ TwitterPlugin::directMessages( const QList< QTweetDMStatus > &messages )
|
||||
peerData["node"] = QVariant::fromValue< QString >( splitNode[0] );
|
||||
peerData["dirty"] = QVariant::fromValue< bool >( true );
|
||||
|
||||
QMetaObject::invokeMethod( this, "registerOffer", Q_ARG( QString, status.senderScreenName() ), QGenericArgument( "QHash< QString, QVariant >", (const void*)&peerData ) );
|
||||
QMetaObject::invokeMethod( this, "registerOffer", Q_ARG( QString, status.senderScreenName() ), Q_ARG( QVariantHash, peerData ) );
|
||||
|
||||
if ( Database::instance()->dbid().startsWith( splitNode[1] ) )
|
||||
{
|
||||
@@ -605,7 +608,7 @@ TwitterPlugin::directMessages( const QList< QTweetDMStatus > &messages )
|
||||
}
|
||||
|
||||
void
|
||||
TwitterPlugin::registerOffer( const QString &screenName, const QHash< QString, QVariant > &peerData )
|
||||
TwitterPlugin::registerOffer( const QString &screenName, const QVariantHash &peerData )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
|
||||
@@ -618,7 +621,7 @@ TwitterPlugin::registerOffer( const QString &screenName, const QHash< QString, Q
|
||||
if ( !m_cachedAvatars.contains( screenName ) )
|
||||
QMetaObject::invokeMethod( this, "fetchAvatar", Q_ARG( QString, screenName ) );
|
||||
|
||||
QHash< QString, QVariant > _peerData( peerData );
|
||||
QVariantHash _peerData( peerData );
|
||||
|
||||
if ( _peerData.contains( "dirty" ) )
|
||||
{
|
||||
@@ -646,8 +649,11 @@ TwitterPlugin::registerOffer( const QString &screenName, const QHash< QString, Q
|
||||
needToSend = true;
|
||||
}
|
||||
|
||||
if ( !m_keyCache.contains( _peerData["okey"].toString() ) )
|
||||
if ( _peerData.contains( "rekey" ) || !m_keyCache.contains( _peerData["okey"].toString() ) )
|
||||
{
|
||||
_peerData.remove( "rekey" );
|
||||
needToAddToCache = true;
|
||||
}
|
||||
|
||||
if ( !_peerData.contains( "ohst" ) || !_peerData.contains( "oprt" ) ||
|
||||
_peerData["ohst"].toString() != Servent::instance()->externalAddress() ||
|
||||
@@ -668,7 +674,7 @@ TwitterPlugin::registerOffer( const QString &screenName, const QHash< QString, Q
|
||||
_peerData["oprt"] = QVariant::fromValue< int >( Servent::instance()->externalPort() );
|
||||
peersChanged = true;
|
||||
if( !Servent::instance()->externalAddress().isEmpty() && !Servent::instance()->externalPort() == 0 )
|
||||
QMetaObject::invokeMethod( this, "sendOffer", Q_ARG( QString, screenName ), QGenericArgument( "QHash< QString, QVariant >", (const void*)&_peerData ) );
|
||||
QMetaObject::invokeMethod( this, "sendOffer", Q_ARG( QString, screenName ), Q_ARG( QVariantHash, _peerData ) );
|
||||
else
|
||||
qDebug() << "TwitterPlugin did not send offer because external address is " << Servent::instance()->externalAddress() << " and external port is " << Servent::instance()->externalPort();
|
||||
}
|
||||
@@ -676,17 +682,17 @@ TwitterPlugin::registerOffer( const QString &screenName, const QHash< QString, Q
|
||||
if ( peersChanged )
|
||||
{
|
||||
_peerData["lastseen"] = QString::number( QDateTime::currentMSecsSinceEpoch() );
|
||||
m_cachedPeers[screenName] = QVariant::fromValue< QHash< QString, QVariant > >( _peerData );
|
||||
setTwitterCachedPeers( m_cachedPeers );
|
||||
m_cachedPeers[screenName] = QVariant::fromValue< QVariantHash >( _peerData );
|
||||
syncConfig();
|
||||
}
|
||||
|
||||
if ( m_state == Connected && _peerData.contains( "host" ) && _peerData.contains( "port" ) && _peerData.contains( "pkey" ) )
|
||||
QMetaObject::invokeMethod( this, "makeConnection", Q_ARG( QString, screenName ), QGenericArgument( "QHash< QString, QVariant >", (const void*)&_peerData ) );
|
||||
QMetaObject::invokeMethod( this, "makeConnection", Q_ARG( QString, screenName ), Q_ARG( QVariantHash, _peerData ) );
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
TwitterPlugin::sendOffer( const QString &screenName, const QHash< QString, QVariant > &peerData )
|
||||
TwitterPlugin::sendOffer( const QString &screenName, const QVariantHash &peerData )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
QString offerString = QString( "TOMAHAWKPEER:Host=%1:Port=%2:Node=%3*%4:PKey=%5" ).arg( peerData["ohst"].toString() )
|
||||
@@ -700,7 +706,7 @@ TwitterPlugin::sendOffer( const QString &screenName, const QHash< QString, QVari
|
||||
}
|
||||
|
||||
void
|
||||
TwitterPlugin::makeConnection( const QString &screenName, const QHash< QString, QVariant > &peerData )
|
||||
TwitterPlugin::makeConnection( const QString &screenName, const QVariantHash &peerData )
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
if ( !peerData.contains( "host" ) || !peerData.contains( "port" ) || !peerData.contains( "pkey" ) || !peerData.contains( "node" ) ||
|
||||
@@ -709,6 +715,14 @@ TwitterPlugin::makeConnection( const QString &screenName, const QHash< QString,
|
||||
qDebug() << "TwitterPlugin could not find host and/or port and/or pkey and/or node for peer " << screenName;
|
||||
return;
|
||||
}
|
||||
|
||||
if ( peerData["host"].toString() == Servent::instance()->externalAddress() &&
|
||||
peerData["port"].toInt() == Servent::instance()->externalPort() )
|
||||
{
|
||||
qDebug() << "TwitterPlugin asked to make connection to our own host and port, ignoring " << screenName;
|
||||
return;
|
||||
}
|
||||
|
||||
QString friendlyName = QString( '@' + screenName );
|
||||
if ( !Servent::instance()->connectedToSession( peerData["node"].toString() ) )
|
||||
Servent::instance()->connectToPeer( peerData["host"].toString(),
|
||||
@@ -1022,7 +1036,7 @@ TwitterPlugin::setTwitterCachedDirectMessagesSinceId( qint64 cachedId )
|
||||
TomahawkSettings::instance()->setValue( pluginId() + "/cacheddirectmessagessinceid", cachedId );
|
||||
}
|
||||
|
||||
QHash<QString, QVariant>
|
||||
QVariantHash
|
||||
TwitterPlugin::twitterCachedPeers() const
|
||||
{
|
||||
TomahawkSettings* s = TomahawkSettings::instance();
|
||||
@@ -1047,13 +1061,14 @@ TwitterPlugin::twitterCachedPeers() const
|
||||
}
|
||||
s->endGroup();
|
||||
|
||||
return s->value( pluginId() + "/cachedpeers", QHash<QString, QVariant>() ).toHash();
|
||||
return s->value( pluginId() + "/cachedpeers", QVariantHash() ).toHash();
|
||||
}
|
||||
|
||||
void
|
||||
TwitterPlugin::setTwitterCachedPeers( const QHash<QString, QVariant> &cachedPeers )
|
||||
TwitterPlugin::setTwitterCachedPeers( const QVariantHash &cachedPeers )
|
||||
{
|
||||
TomahawkSettings::instance()->setValue( pluginId() + "/cachedpeers", cachedPeers );
|
||||
TomahawkSettings::instance()->sync();
|
||||
}
|
||||
|
||||
Q_EXPORT_PLUGIN2( sipfactory, TwitterFactory )
|
||||
|
@@ -108,14 +108,15 @@ private slots:
|
||||
void directMessagePosted( const QTweetDMStatus &message );
|
||||
void directMessagePostError( QTweetNetBase::ErrorCode errorCode, const QString &message );
|
||||
void directMessageDestroyed( const QTweetDMStatus &message );
|
||||
void registerOffer( const QString &screenName, const QHash< QString, QVariant > &peerdata );
|
||||
void sendOffer( const QString &screenName, const QHash< QString, QVariant > &peerdata );
|
||||
void makeConnection( const QString &screenName, const QHash< QString, QVariant > &peerdata );
|
||||
void registerOffer( const QString &screenName, const QVariantHash &peerdata );
|
||||
void sendOffer( const QString &screenName, const QVariantHash &peerdata );
|
||||
void makeConnection( const QString &screenName, const QVariantHash &peerdata );
|
||||
void fetchAvatar( const QString &screenName );
|
||||
void avatarUserDataSlot( const QTweetUser &user );
|
||||
void profilePicReply();
|
||||
|
||||
private:
|
||||
inline void syncConfig() { setTwitterCachedPeers( m_cachedPeers ); }
|
||||
bool refreshTwitterAuth();
|
||||
void parseGotTomahawk( const QRegExp ®ex, const QString &screenName, const QString &text );
|
||||
// handle per-plugin config
|
||||
@@ -133,8 +134,8 @@ private:
|
||||
void setTwitterCachedMentionsSinceId( qint64 sinceid );
|
||||
qint64 twitterCachedDirectMessagesSinceId() const;
|
||||
void setTwitterCachedDirectMessagesSinceId( qint64 sinceid );
|
||||
QHash<QString, QVariant> twitterCachedPeers() const;
|
||||
void setTwitterCachedPeers( const QHash<QString, QVariant> &cachedPeers );
|
||||
QVariantHash twitterCachedPeers() const;
|
||||
void setTwitterCachedPeers( const QVariantHash &cachedPeers );
|
||||
|
||||
QWeakPointer< TomahawkOAuthTwitter > m_twitterAuth;
|
||||
QWeakPointer< QTweetFriendsTimeline > m_friendsTimeline;
|
||||
@@ -146,14 +147,13 @@ private:
|
||||
bool m_isAuthed;
|
||||
QTimer m_checkTimer;
|
||||
QTimer m_connectTimer;
|
||||
QTimer m_dmPollTimer;
|
||||
qint64 m_cachedFriendsSinceId;
|
||||
qint64 m_cachedMentionsSinceId;
|
||||
qint64 m_cachedDirectMessagesSinceId;
|
||||
QHash< QString, QVariant > m_cachedPeers;
|
||||
QVariantHash m_cachedPeers;
|
||||
QHash< QString, QPixmap > m_cachedAvatars;
|
||||
QSet<QString> m_keyCache;
|
||||
bool m_finishedFriends;
|
||||
bool m_finishedMentions;
|
||||
ConnectionState m_state;
|
||||
|
||||
QWeakPointer<TwitterConfigWidget > m_configWidget;
|
||||
|
@@ -28,7 +28,7 @@
|
||||
#include "widgets/playlisttypeselectordlg.h"
|
||||
#include <playlist/dynamic/GeneratorInterface.h>
|
||||
#include "utils/logger.h"
|
||||
#include <globalactionmanager.h>
|
||||
#include "dropjob.h"
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
@@ -122,7 +122,7 @@ CategoryAddItem::icon() const
|
||||
bool
|
||||
CategoryAddItem::willAcceptDrag( const QMimeData* data ) const
|
||||
{
|
||||
if ( ( m_categoryType == SourcesModel::PlaylistsCategory || m_categoryType == SourcesModel::StationsCategory ) && GlobalActionManager::instance()->acceptsMimeData( data ) )
|
||||
if ( ( m_categoryType == SourcesModel::PlaylistsCategory || m_categoryType == SourcesModel::StationsCategory ) && DropJob::acceptsMimeData( data ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -133,9 +133,96 @@ CategoryAddItem::willAcceptDrag( const QMimeData* data ) const
|
||||
bool
|
||||
CategoryAddItem::dropMimeData( const QMimeData* data, Qt::DropAction )
|
||||
{
|
||||
// As DropJob always converts dropped items to query_ptrs for all tracks we need to extract album/artist metadata ourselves for stations
|
||||
if ( m_categoryType == SourcesModel::StationsCategory &&
|
||||
( data->hasFormat( "application/tomahawk.metadata.artist" ) || data->hasFormat( "application/tomahawk.metadata.album" ) ) )
|
||||
{
|
||||
QByteArray mimeData;
|
||||
if ( data->hasFormat( "application/tomahawk.metadata.artist" ) )
|
||||
mimeData = data->data( "application/tomahawk.metadata.artist" );
|
||||
else if ( data->hasFormat( "application/tomahawk.metadata.album" ) )
|
||||
mimeData = data->data( "application/tomahawk.metadata.album" );
|
||||
|
||||
QDataStream stream( &mimeData, QIODevice::ReadOnly );
|
||||
|
||||
dynplaylist_ptr newpl = DynamicPlaylist::create( SourceList::instance()->getLocal(), uuid(), QString(), "", SourceList::instance()->getLocal()->friendlyName(), OnDemand, false );
|
||||
newpl->setMode( OnDemand );
|
||||
|
||||
QString firstArtist;
|
||||
// now we want to add each artist as a filter...
|
||||
QList< dyncontrol_ptr > contrls;
|
||||
while ( !stream.atEnd() )
|
||||
{
|
||||
QString artist;
|
||||
stream >> artist;
|
||||
if ( firstArtist.isEmpty() )
|
||||
firstArtist = artist;
|
||||
|
||||
QString album;
|
||||
if ( data->hasFormat( "application/tomahawk.metadata.album" ) )
|
||||
stream >> album; // throw away album title... we only create artists filters for now
|
||||
|
||||
dyncontrol_ptr c = newpl->generator()->createControl( "Artist" );
|
||||
c->setInput( QString( "%1" ).arg( artist ) );
|
||||
contrls << c;
|
||||
}
|
||||
|
||||
QString name = firstArtist.isEmpty() ? tr( "New Station" ) : tr( "%1 Station" ).arg( firstArtist );
|
||||
newpl->rename( name );
|
||||
newpl->createNewRevision( uuid(), newpl->currentrevision(), newpl->type(), contrls );
|
||||
|
||||
ViewManager::instance()->show( newpl );
|
||||
return true;
|
||||
}
|
||||
|
||||
// This could be needed once echonest supports filtering by album.
|
||||
// If they never will, or if they do and this code still is not used, throw it away!
|
||||
// If you enable this, make sure to remove the checks for album above.
|
||||
|
||||
/* if ( m_categoryType == SourcesModel::StationsCategory && data->hasFormat( "application/tomahawk.metadata.album" ) )
|
||||
{
|
||||
QByteArray mimeData = data->data( "application/tomahawk.metadata.album" );
|
||||
QDataStream stream( &mimeData, QIODevice::ReadOnly );
|
||||
|
||||
dynplaylist_ptr newpl = DynamicPlaylist::create( SourceList::instance()->getLocal(), uuid(), QString(), "", SourceList::instance()->getLocal()->friendlyName(), OnDemand, false );
|
||||
newpl->setMode( OnDemand );
|
||||
|
||||
QString firstAlbum;
|
||||
// now we want to add each artist as a filter...
|
||||
QList< dyncontrol_ptr > contrls;
|
||||
while ( !stream.atEnd() )
|
||||
{
|
||||
QString artist;
|
||||
stream >> artist;
|
||||
QString album;
|
||||
stream >> album;
|
||||
|
||||
if ( firstAlbum.isEmpty() )
|
||||
{
|
||||
firstAlbum = album;
|
||||
}
|
||||
|
||||
dyncontrol_ptr c = newpl->generator()->createControl( "Album" );
|
||||
c->setInput( QString( "%1" ).arg( artist ) );
|
||||
contrls << c;
|
||||
}
|
||||
|
||||
QString name = firstAlbum.isEmpty() ? tr( "New Station" ) : tr( "%1 Station" ).arg( firstAlbum );
|
||||
newpl->rename( name );
|
||||
newpl->createNewRevision( uuid(), newpl->currentrevision(), newpl->type(), contrls );
|
||||
|
||||
ViewManager::instance()->show( newpl );
|
||||
// Give a shot to try to rename it. The playlist has to be created first. ugly.
|
||||
QTimer::singleShot( 300, APP->mainWindow()->sourceTreeView(), SLOT( renamePlaylist() ) );
|
||||
return true;
|
||||
|
||||
} */
|
||||
|
||||
|
||||
// Create a new playlist seeded with these items
|
||||
connect( GlobalActionManager::instance(), SIGNAL( tracks( QList< Tomahawk::query_ptr > ) ), this, SLOT( parsedDroppedTracks( QList< Tomahawk::query_ptr > ) ) );
|
||||
GlobalActionManager::instance()->tracksFromMimeData( data );
|
||||
DropJob *dj = new DropJob();
|
||||
connect( dj, SIGNAL( tracks( QList< Tomahawk::query_ptr > ) ), this, SLOT( parsedDroppedTracks( QList< Tomahawk::query_ptr > ) ) );
|
||||
dj->tracksFromMimeData( data );
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -143,7 +230,6 @@ CategoryAddItem::dropMimeData( const QMimeData* data, Qt::DropAction )
|
||||
void
|
||||
CategoryAddItem::parsedDroppedTracks( const QList< query_ptr >& tracks )
|
||||
{
|
||||
disconnect( GlobalActionManager::instance(), SIGNAL( tracks( QList< Tomahawk::query_ptr > ) ), this, SLOT( parsedDroppedTracks( QList< Tomahawk::query_ptr > ) ) );
|
||||
if( m_categoryType == SourcesModel::PlaylistsCategory ) {
|
||||
|
||||
playlist_ptr newpl = Playlist::create( SourceList::instance()->getLocal(), uuid(), "New Playlist", "", SourceList::instance()->getLocal()->friendlyName(), false, tracks );
|
||||
|
@@ -139,7 +139,7 @@ CollectionItem::text() const
|
||||
|
||||
|
||||
int
|
||||
CollectionItem::peerSortValue() const
|
||||
CollectionItem::IDValue() const
|
||||
{
|
||||
if( m_source.isNull() )
|
||||
return -1;
|
||||
@@ -150,6 +150,18 @@ CollectionItem::peerSortValue() const
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
CollectionItem::peerSortValue() const
|
||||
{
|
||||
if( m_source.isNull() )
|
||||
return -1;
|
||||
if( m_source->isLocal() )
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CollectionItem::activate()
|
||||
{
|
||||
@@ -225,6 +237,8 @@ CollectionItem::playlistDeletedInternal( SourceTreeItem* parent, const T& p )
|
||||
parent->beginRowsRemoved( i, i );
|
||||
parent->removeChild( pl );
|
||||
parent->endRowsRemoved();
|
||||
|
||||
delete pl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@@ -37,6 +37,7 @@ public:
|
||||
virtual void activate();
|
||||
virtual QIcon icon() const;
|
||||
virtual int peerSortValue() const;
|
||||
virtual int IDValue() const;
|
||||
|
||||
Tomahawk::source_ptr source() const;
|
||||
|
||||
|
@@ -28,7 +28,7 @@
|
||||
#include "collectionitem.h"
|
||||
#include "utils/tomahawkutils.h"
|
||||
#include "utils/logger.h"
|
||||
#include "globalactionmanager.h"
|
||||
#include "dropjob.h"
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
@@ -81,6 +81,14 @@ PlaylistItem::onPlaylistChanged()
|
||||
|
||||
int
|
||||
PlaylistItem::peerSortValue() const
|
||||
{
|
||||
// return m_playlist->createdOn();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
PlaylistItem::IDValue() const
|
||||
{
|
||||
return m_playlist->createdOn();
|
||||
}
|
||||
@@ -142,8 +150,9 @@ PlaylistItem::dropMimeData( const QMimeData* data, Qt::DropAction action )
|
||||
data->data( "application/tomahawk.playlist.id" ) == m_playlist->guid() )
|
||||
return false; // don't allow dropping on ourselves
|
||||
|
||||
connect( GlobalActionManager::instance(), SIGNAL( tracks( QList< Tomahawk::query_ptr > ) ), this, SLOT( parsedDroppedTracks( QList< Tomahawk::query_ptr > ) ) );
|
||||
GlobalActionManager::instance()->tracksFromMimeData( data );
|
||||
DropJob *dj = new DropJob();
|
||||
connect( dj, SIGNAL( tracks( QList< Tomahawk::query_ptr > ) ), this, SLOT( parsedDroppedTracks( QList< Tomahawk::query_ptr > ) ) );
|
||||
dj->tracksFromMimeData( data );
|
||||
|
||||
// TODO cant' know if it works or not yet...
|
||||
return true;
|
||||
@@ -152,7 +161,6 @@ PlaylistItem::dropMimeData( const QMimeData* data, Qt::DropAction action )
|
||||
void
|
||||
PlaylistItem::parsedDroppedTracks( const QList< query_ptr >& tracks)
|
||||
{
|
||||
disconnect( GlobalActionManager::instance(), SIGNAL( tracks( QList< Tomahawk::query_ptr > ) ), this, SLOT( parsedDroppedTracks( QList< Tomahawk::query_ptr > ) ) );
|
||||
if ( tracks.count() && !m_playlist.isNull() && m_playlist->author()->isLocal() )
|
||||
{
|
||||
qDebug() << "on playlist:" << m_playlist->title() << m_playlist->guid() << m_playlist->currentrevision();
|
||||
@@ -237,6 +245,14 @@ DynamicPlaylistItem::onDynamicPlaylistLoaded( DynamicPlaylistRevision revision )
|
||||
|
||||
int
|
||||
DynamicPlaylistItem::peerSortValue() const
|
||||
{
|
||||
// return m_dynplaylist->createdOn();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
DynamicPlaylistItem::IDValue() const
|
||||
{
|
||||
return m_dynplaylist->createdOn();
|
||||
}
|
||||
|
@@ -38,6 +38,7 @@ public:
|
||||
virtual QIcon icon() const;
|
||||
virtual bool setData(const QVariant& v, bool role);
|
||||
virtual int peerSortValue() const;
|
||||
virtual int IDValue() const;
|
||||
|
||||
virtual bool activateCurrent();
|
||||
|
||||
@@ -67,6 +68,7 @@ public:
|
||||
virtual bool willAcceptDrag( const QMimeData* data ) const;
|
||||
virtual void activate();
|
||||
virtual int peerSortValue() const;
|
||||
virtual int IDValue() const;
|
||||
virtual QIcon icon() const;
|
||||
|
||||
virtual bool activateCurrent();
|
||||
|
@@ -55,6 +55,7 @@ public:
|
||||
virtual bool dropMimeData( const QMimeData*, Qt::DropAction ) { return false; }
|
||||
virtual bool setData( const QVariant&, bool ) { return false; }
|
||||
virtual int peerSortValue() const { return 0; } // How to sort relative to peers in the tree.
|
||||
virtual int IDValue() const { return 0; }
|
||||
|
||||
/// don't call me unless you are a sourcetreeitem. i prefer this to making everyone a friend
|
||||
void beginRowsAdded( int from, int to ) { emit beginChildRowsAdded( from, to ); }
|
||||
|
@@ -33,6 +33,7 @@
|
||||
|
||||
#include "utils/logger.h"
|
||||
#include "globalactionmanager.h"
|
||||
#include "dropjob.h"
|
||||
#include "items/playlistitems.h"
|
||||
|
||||
using namespace Tomahawk;
|
||||
@@ -105,6 +106,8 @@ SourcesModel::data( const QModelIndex& index, int role ) const
|
||||
return itemFromIndex( index )->icon();
|
||||
case SourcesModel::SortRole:
|
||||
return itemFromIndex( index )->peerSortValue();
|
||||
case SourcesModel::IDRole:
|
||||
return itemFromIndex( index )->IDValue();
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
@@ -175,7 +178,7 @@ SourcesModel::setData( const QModelIndex& index, const QVariant& value, int role
|
||||
QStringList
|
||||
SourcesModel::mimeTypes() const
|
||||
{
|
||||
return GlobalActionManager::instance()->mimeTypes();
|
||||
return DropJob::mimeTypes();
|
||||
}
|
||||
|
||||
|
||||
|
@@ -61,7 +61,8 @@ public:
|
||||
enum Roles {
|
||||
SourceTreeItemRole = Qt::UserRole + 10,
|
||||
SourceTreeItemTypeRole = Qt::UserRole + 11,
|
||||
SortRole = Qt::UserRole + 12
|
||||
SortRole = Qt::UserRole + 12,
|
||||
IDRole = Qt::UserRole + 13
|
||||
};
|
||||
|
||||
SourcesModel( QObject* parent = 0 );
|
||||
|
@@ -20,6 +20,7 @@
|
||||
|
||||
#include <QTreeView>
|
||||
|
||||
#include "sourcelist.h"
|
||||
#include "sourcesmodel.h"
|
||||
#include "sourcetree/items/collectionitem.h"
|
||||
|
||||
@@ -36,7 +37,6 @@ SourcesProxyModel::SourcesProxyModel( SourcesModel* model, QObject* parent )
|
||||
|
||||
setSourceModel( model );
|
||||
|
||||
|
||||
if ( model && model->metaObject()->indexOfSignal( "expandRequest(QModelIndex)" ) > -1 )
|
||||
connect( model, SIGNAL( expandRequest( QModelIndex ) ), this, SLOT( expandRequested( QModelIndex ) ) );
|
||||
if ( model && model->metaObject()->indexOfSignal( "selectRequest(QModelIndex)" ) > -1 )
|
||||
@@ -51,13 +51,13 @@ SourcesProxyModel::showOfflineSources( bool offlineSourcesShown )
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
SourcesProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent ) const
|
||||
{
|
||||
if ( !m_filtered )
|
||||
return true;
|
||||
|
||||
|
||||
CollectionItem* sti = qobject_cast< CollectionItem* >( m_model->data( sourceModel()->index( sourceRow, 0, sourceParent ), SourcesModel::SourceTreeItemRole ).value< SourceTreeItem* >() );
|
||||
if ( sti )
|
||||
{
|
||||
@@ -70,6 +70,7 @@ SourcesProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex& sourcePar
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SourcesProxyModel::selectRequested( const QModelIndex& idx )
|
||||
{
|
||||
@@ -77,6 +78,7 @@ SourcesProxyModel::selectRequested( const QModelIndex& idx )
|
||||
emit selectRequest( mapFromSource( idx ) );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SourcesProxyModel::expandRequested( const QModelIndex& idx )
|
||||
{
|
||||
@@ -84,3 +86,18 @@ SourcesProxyModel::expandRequested( const QModelIndex& idx )
|
||||
emit expandRequest( mapFromSource( idx ) );
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
SourcesProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right ) const
|
||||
{
|
||||
if ( m_model->data( left, SourcesModel::SortRole ) != m_model->data( right, SourcesModel::SortRole ) )
|
||||
return ( m_model->data( left, SourcesModel::SortRole ).toInt() < m_model->data( right, SourcesModel::SortRole ).toInt() );
|
||||
|
||||
const QString& lefts = left.data().toString().toLower();
|
||||
const QString& rights = right.data().toString().toLower();
|
||||
|
||||
if ( lefts == rights )
|
||||
return ( m_model->data( left, SourcesModel::IDRole ).toInt() < m_model->data( right, SourcesModel::IDRole ).toInt() );
|
||||
else
|
||||
return QString::localeAwareCompare( lefts, rights ) < 0;
|
||||
}
|
||||
|
@@ -42,6 +42,7 @@ signals:
|
||||
|
||||
protected:
|
||||
bool filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent ) const;
|
||||
bool lessThan( const QModelIndex& left, const QModelIndex& right ) const;
|
||||
|
||||
private:
|
||||
SourcesModel* m_model;
|
||||
|
@@ -37,7 +37,8 @@
|
||||
#include "audio/audioengine.h"
|
||||
#include "sourceplaylistinterface.h"
|
||||
#include "tomahawksettings.h"
|
||||
#include <globalactionmanager.h>
|
||||
#include "globalactionmanager.h"
|
||||
#include "dropjob.h"
|
||||
|
||||
#include "utils/logger.h"
|
||||
|
||||
@@ -162,7 +163,7 @@ SourceTreeView::setupMenus()
|
||||
if ( pi && dynamic_cast< SourcePlaylistInterface* >( pi ) )
|
||||
{
|
||||
SourcePlaylistInterface* sourcepi = dynamic_cast< SourcePlaylistInterface* >( pi );
|
||||
if ( !sourcepi->source().isNull() && sourcepi->source()->id() == source->id() )
|
||||
if ( !sourcepi->source().isNull() && sourcepi->source()->id() == source->id() && !AudioEngine::instance()->state() == AudioEngine::Stopped )
|
||||
{
|
||||
m_latchOnAction->setText( tr( "&Catch Up" ) );
|
||||
m_latchMenu.addSeparator();
|
||||
@@ -439,7 +440,7 @@ SourceTreeView::dragEnterEvent( QDragEnterEvent* event )
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
QTreeView::dragEnterEvent( event );
|
||||
|
||||
if ( GlobalActionManager::instance()->acceptsMimeData( event->mimeData() ) )
|
||||
if ( DropJob::acceptsMimeData( event->mimeData() ) )
|
||||
{
|
||||
m_dragging = true;
|
||||
m_dropRect = QRect();
|
||||
@@ -470,7 +471,7 @@ SourceTreeView::dragMoveEvent( QDragMoveEvent* event )
|
||||
bool accept = false;
|
||||
QTreeView::dragMoveEvent( event );
|
||||
|
||||
if ( GlobalActionManager::instance()->acceptsMimeData( event->mimeData() ) )
|
||||
if ( DropJob::acceptsMimeData( event->mimeData() ) )
|
||||
{
|
||||
setDirtyRegion( m_dropRect );
|
||||
const QPoint pos = event->pos();
|
||||
|
@@ -141,6 +141,7 @@ TomahawkApp::init()
|
||||
m_mainwindow = 0;
|
||||
m_headless = arguments().contains( "--headless" );
|
||||
setWindowIcon( QIcon( RESPATH "icons/tomahawk-icon-128x128.png" ) );
|
||||
setQuitOnLastWindowClosed( false );
|
||||
#endif
|
||||
|
||||
registerMetaTypes();
|
||||
@@ -193,8 +194,6 @@ TomahawkApp::init()
|
||||
|
||||
Tomahawk::setApplicationHandler( this );
|
||||
increaseMaxFileDescriptors();
|
||||
|
||||
setQuitOnLastWindowClosed( false );
|
||||
#endif
|
||||
|
||||
// Connect up shortcuts
|
||||
@@ -222,6 +221,7 @@ TomahawkApp::init()
|
||||
tDebug() << "Init MainWindow.";
|
||||
m_mainwindow = new TomahawkWindow();
|
||||
m_mainwindow->setWindowTitle( "Tomahawk" );
|
||||
m_mainwindow->setObjectName( "TH_Main_Window" );
|
||||
m_mainwindow->show();
|
||||
}
|
||||
#endif
|
||||
|
243
thirdparty/libqnetwm/libqnetwm/fixx11h.h
vendored
Normal file
243
thirdparty/libqnetwm/libqnetwm/fixx11h.h
vendored
Normal file
@@ -0,0 +1,243 @@
|
||||
//#ifdef don't do this, this file is supposed to be included
|
||||
//#define multiple times
|
||||
|
||||
/* Usage:
|
||||
|
||||
If you get compile errors caused by X11 includes (the line
|
||||
where first error appears contains word like None, Unsorted,
|
||||
Below, etc.), put #include <fixx11h.h> in the .cpp file
|
||||
(not .h file!) between the place where X11 headers are
|
||||
included and the place where the file with compile
|
||||
error is included (or the place where the compile error
|
||||
in the .cpp file occurs).
|
||||
|
||||
This file remaps X11 #defines to const variables or
|
||||
inline functions. The side effect may be that these
|
||||
symbols may now refer to different variables
|
||||
(e.g. if X11 #defined NoButton, after this file
|
||||
is included NoButton would no longer be X11's
|
||||
NoButton, but Qt::NoButton instead). At this time,
|
||||
there's no conflict known that could cause problems.
|
||||
|
||||
The original X11 symbols are still accessible
|
||||
(e.g. for None) as X::None, XNone, and also still
|
||||
None, unless name lookup finds different None
|
||||
first (in the current class, etc.)
|
||||
|
||||
Use 'Unsorted', 'Bool' and 'index' as templates.
|
||||
|
||||
*/
|
||||
|
||||
namespace X
|
||||
{
|
||||
|
||||
// template --->
|
||||
// Affects: Should be without side effects.
|
||||
#ifdef Unsorted
|
||||
#ifndef FIXX11H_Unsorted
|
||||
#define FIXX11H_Unsorted
|
||||
const int XUnsorted = Unsorted;
|
||||
#undef Unsorted
|
||||
const int Unsorted = XUnsorted;
|
||||
#endif
|
||||
#undef Unsorted
|
||||
#endif
|
||||
// template <---
|
||||
|
||||
// Affects: Should be without side effects.
|
||||
#ifdef None
|
||||
#ifndef FIXX11H_None
|
||||
#define FIXX11H_None
|
||||
const XID XNone = None;
|
||||
#undef None
|
||||
const XID None = XNone;
|
||||
#endif
|
||||
#undef None
|
||||
#endif
|
||||
|
||||
// template --->
|
||||
// Affects: Should be without side effects.
|
||||
#ifdef Bool
|
||||
#ifndef FIXX11H_Bool
|
||||
#define FIXX11H_Bool
|
||||
typedef Bool XBool;
|
||||
#undef Bool
|
||||
typedef XBool Bool;
|
||||
#endif
|
||||
#undef Bool
|
||||
#endif
|
||||
|
||||
#ifdef FontChange
|
||||
#ifndef FIXX11H_FontChange
|
||||
#define FIXX11H_FontChange
|
||||
const int XFontChange = FontChange;
|
||||
#undef FontChange
|
||||
const int FontChange = XFontChange;
|
||||
#endif
|
||||
#undef FontChange
|
||||
#endif
|
||||
// template <---
|
||||
|
||||
// Affects: Should be without side effects.
|
||||
#ifdef KeyPress
|
||||
#ifndef FIXX11H_KeyPress
|
||||
#define FIXX11H_KeyPress
|
||||
const int XKeyPress = KeyPress;
|
||||
#undef KeyPress
|
||||
const int KeyPress = XKeyPress;
|
||||
#endif
|
||||
#undef KeyPress
|
||||
#endif
|
||||
|
||||
// Affects: Should be without side effects.
|
||||
#ifdef KeyRelease
|
||||
#ifndef FIXX11H_KeyRelease
|
||||
#define FIXX11H_KeyRelease
|
||||
const int XKeyRelease = KeyRelease;
|
||||
#undef KeyRelease
|
||||
const int KeyRelease = XKeyRelease;
|
||||
#endif
|
||||
#undef KeyRelease
|
||||
#endif
|
||||
|
||||
// Affects: Should be without side effects.
|
||||
#ifdef Above
|
||||
#ifndef FIXX11H_Above
|
||||
#define FIXX11H_Above
|
||||
const int XAbove = Above;
|
||||
#undef Above
|
||||
const int Above = XAbove;
|
||||
#endif
|
||||
#undef Above
|
||||
#endif
|
||||
|
||||
// Affects: Should be without side effects.
|
||||
#ifdef Below
|
||||
#ifndef FIXX11H_Below
|
||||
#define FIXX11H_Below
|
||||
const int XBelow = Below;
|
||||
#undef Below
|
||||
const int Below = XBelow;
|
||||
#endif
|
||||
#undef Below
|
||||
#endif
|
||||
|
||||
// Affects: Should be without side effects.
|
||||
#ifdef FocusIn
|
||||
#ifndef FIXX11H_FocusIn
|
||||
#define FIXX11H_FocusIn
|
||||
const int XFocusIn = FocusIn;
|
||||
#undef FocusIn
|
||||
const int FocusIn = XFocusIn;
|
||||
#endif
|
||||
#undef FocusIn
|
||||
#endif
|
||||
|
||||
// Affects: Should be without side effects.
|
||||
#ifdef FocusOut
|
||||
#ifndef FIXX11H_FocusOut
|
||||
#define FIXX11H_FocusOut
|
||||
const int XFocusOut = FocusOut;
|
||||
#undef FocusOut
|
||||
const int FocusOut = XFocusOut;
|
||||
#endif
|
||||
#undef FocusOut
|
||||
#endif
|
||||
|
||||
// Affects: Should be without side effects.
|
||||
#ifdef Always
|
||||
#ifndef FIXX11H_Always
|
||||
#define FIXX11H_Always
|
||||
const int XAlways = Always;
|
||||
#undef Always
|
||||
const int Always = XAlways;
|
||||
#endif
|
||||
#undef Always
|
||||
#endif
|
||||
|
||||
// Affects: Should be without side effects.
|
||||
#ifdef Success
|
||||
#ifndef FIXX11H_Success
|
||||
#define FIXX11H_Success
|
||||
const int XSuccess = Success;
|
||||
#undef Success
|
||||
const int Success = XSuccess;
|
||||
#endif
|
||||
#undef Success
|
||||
#endif
|
||||
|
||||
// Affects: Should be without side effects.
|
||||
#ifdef GrayScale
|
||||
#ifndef FIXX11H_GrayScale
|
||||
#define FIXX11H_GrayScale
|
||||
const int XGrayScale = GrayScale;
|
||||
#undef GrayScale
|
||||
const int GrayScale = XGrayScale;
|
||||
#endif
|
||||
#undef GrayScale
|
||||
#endif
|
||||
|
||||
// Affects: Should be without side effects.
|
||||
#ifdef Status
|
||||
#ifndef FIXX11H_Status
|
||||
#define FIXX11H_Status
|
||||
typedef Status XStatus;
|
||||
#undef Status
|
||||
typedef XStatus Status;
|
||||
#endif
|
||||
#undef Status
|
||||
#endif
|
||||
|
||||
// Affects: Should be without side effects.
|
||||
#ifdef CursorShape
|
||||
#ifndef FIXX11H_CursorShape
|
||||
#define FIXX11H_CursorShape
|
||||
const int XCursorShape = CursorShape;
|
||||
#undef CursorShape
|
||||
const int CursorShape = CursorShape;
|
||||
#endif
|
||||
#undef CursorShape
|
||||
#endif
|
||||
|
||||
// template --->
|
||||
// Affects: Should be without side effects.
|
||||
#ifdef index
|
||||
#ifndef FIXX11H_index
|
||||
#define FIXX11H_index
|
||||
inline
|
||||
char* Xindex( const char* s, int c )
|
||||
{
|
||||
return index( s, c );
|
||||
}
|
||||
#undef index
|
||||
inline
|
||||
char* index( const char* s, int c )
|
||||
{
|
||||
return Xindex( s, c );
|
||||
}
|
||||
#endif
|
||||
#undef index
|
||||
#endif
|
||||
// template <---
|
||||
|
||||
#ifdef rindex
|
||||
// Affects: Should be without side effects.
|
||||
#ifndef FIXX11H_rindex
|
||||
#define FIXX11H_rindex
|
||||
inline
|
||||
char* Xrindex( const char* s, int c )
|
||||
{
|
||||
return rindex( s, c );
|
||||
}
|
||||
#undef rindex
|
||||
inline
|
||||
char* rindex( const char* s, int c )
|
||||
{
|
||||
return Xrindex( s, c );
|
||||
}
|
||||
#endif
|
||||
#undef rindex
|
||||
#endif
|
||||
}
|
||||
|
||||
using namespace X;
|
735
thirdparty/libqnetwm/libqnetwm/netwm.cpp
vendored
Normal file
735
thirdparty/libqnetwm/libqnetwm/netwm.cpp
vendored
Normal file
@@ -0,0 +1,735 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2010 by Dmitry 'Krasu' Baryshev *
|
||||
* ksquirrel.iv@gmail.com *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#include <QX11Info>
|
||||
|
||||
#include <climits>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <strings.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <X11/Xutil.h>
|
||||
|
||||
#if 0
|
||||
#include <X11/extensions/Xcomposite.h>
|
||||
#endif
|
||||
|
||||
#include "netwm.h"
|
||||
|
||||
#define DBG(...) //fprintf(stderr, ##__VA_ARGS__)
|
||||
|
||||
Atom NETWM::UTF8_STRING = 0;
|
||||
Atom NETWM::XROOTPMAP_ID = 0;
|
||||
|
||||
Atom NETWM::WM_STATE = 0;
|
||||
Atom NETWM::WM_CLASS = 0;
|
||||
Atom NETWM::WM_NAME = 0;
|
||||
Atom NETWM::WM_DELETE_WINDOW = 0;
|
||||
Atom NETWM::WM_PROTOCOLS = 0;
|
||||
Atom NETWM::WM_CHANGE_STATE = 0;
|
||||
Atom NETWM::WM_WINDOW_ROLE = 0;
|
||||
|
||||
Atom NETWM::NET_WORKAREA = 0;
|
||||
Atom NETWM::NET_CLIENT_LIST = 0;
|
||||
Atom NETWM::NET_CLIENT_LIST_STACKING = 0;
|
||||
Atom NETWM::NET_NUMBER_OF_DESKTOPS = 0;
|
||||
Atom NETWM::NET_CURRENT_DESKTOP = 0;
|
||||
Atom NETWM::NET_DESKTOP_NAMES = 0;
|
||||
Atom NETWM::NET_ACTIVE_WINDOW = 0;
|
||||
Atom NETWM::NET_CLOSE_WINDOW = 0;
|
||||
Atom NETWM::NET_SUPPORTED = 0;
|
||||
Atom NETWM::NET_WM_DESKTOP = 0;
|
||||
Atom NETWM::NET_SHOWING_DESKTOP = 0;
|
||||
|
||||
Atom NETWM::NET_WM_STATE = 0;
|
||||
Atom NETWM::NET_WM_STATE_MODAL = 0;
|
||||
Atom NETWM::NET_WM_STATE_STICKY = 0;
|
||||
Atom NETWM::NET_WM_STATE_MAXIMIZED_VERT = 0;
|
||||
Atom NETWM::NET_WM_STATE_MAXIMIZED_HORZ = 0;
|
||||
Atom NETWM::NET_WM_STATE_SHADED = 0;
|
||||
Atom NETWM::NET_WM_STATE_SKIP_TASKBAR = 0;
|
||||
Atom NETWM::NET_WM_STATE_SKIP_PAGER = 0;
|
||||
Atom NETWM::NET_WM_STATE_HIDDEN = 0;
|
||||
Atom NETWM::NET_WM_STATE_FULLSCREEN = 0;
|
||||
Atom NETWM::NET_WM_STATE_ABOVE = 0;
|
||||
Atom NETWM::NET_WM_STATE_BELOW = 0;
|
||||
Atom NETWM::NET_WM_STATE_STAYS_ON_TOP = 0;
|
||||
Atom NETWM::NET_WM_STATE_STAYS_ON_BOTTOM = 0;
|
||||
Atom NETWM::NET_WM_STATE_DEMANDS_ATTENTION = 0;
|
||||
|
||||
Atom NETWM::NET_WM_WINDOW_TYPE = 0;
|
||||
Atom NETWM::NET_WM_WINDOW_TYPE_DESKTOP = 0;
|
||||
Atom NETWM::NET_WM_WINDOW_TYPE_DOCK = 0;
|
||||
Atom NETWM::MODERRO_WINDOW_TYPE_DOCK = 0;
|
||||
Atom NETWM::NET_WM_WINDOW_TYPE_TOOLBAR = 0;
|
||||
Atom NETWM::NET_WM_WINDOW_TYPE_MENU = 0;
|
||||
Atom NETWM::NET_WM_WINDOW_TYPE_UTILITY = 0;
|
||||
Atom NETWM::NET_WM_WINDOW_TYPE_SPLASH = 0;
|
||||
Atom NETWM::NET_WM_WINDOW_TYPE_DIALOG = 0;
|
||||
Atom NETWM::NET_WM_WINDOW_TYPE_DROPDOWN_MENU = 0;
|
||||
Atom NETWM::NET_WM_WINDOW_TYPE_POPUP_MENU = 0;
|
||||
Atom NETWM::NET_WM_WINDOW_TYPE_TOOLTIP = 0;
|
||||
Atom NETWM::NET_WM_WINDOW_TYPE_NOTIFICATION = 0;
|
||||
Atom NETWM::NET_WM_WINDOW_TYPE_COMBO = 0;
|
||||
Atom NETWM::NET_WM_WINDOW_TYPE_DND = 0;
|
||||
Atom NETWM::NET_WM_WINDOW_TYPE_NORMAL = 0;
|
||||
Atom NETWM::NET_WM_WINDOW_OPACITY = 0;
|
||||
Atom NETWM::NET_WM_NAME = 0;
|
||||
Atom NETWM::NET_WM_VISIBLE_NAME = 0;
|
||||
Atom NETWM::NET_WM_STRUT = 0;
|
||||
Atom NETWM::NET_WM_STRUT_PARTIAL = 0;
|
||||
Atom NETWM::NET_WM_ICON = 0;
|
||||
Atom NETWM::NET_WM_PID = 0;
|
||||
|
||||
NETWM::net_wm_state::net_wm_state()
|
||||
: modal(0), sticky(0), maximized_vert(0),
|
||||
maximized_horz(0), shaded(0), skip_taskbar(0),
|
||||
skip_pager(0), hidden(0), fullscreen(0),
|
||||
above(0), below(0), stays_on_top(0), stays_on_bottom(0),
|
||||
demands_attention(0), valid(false)
|
||||
{}
|
||||
|
||||
NETWM::net_wm_window_type::net_wm_window_type()
|
||||
: desktop(0), dock(0), toolbar(0),
|
||||
menu(0), utility(0), splash(0), dialog(0),
|
||||
dropdown(0), popup(0), tooltip(0), notification(0),
|
||||
combo(0), dnd(0), normal(0), valid(false)
|
||||
{}
|
||||
|
||||
/**********************************************************/
|
||||
|
||||
void NETWM::init()
|
||||
{
|
||||
Display *dpy = QX11Info::display();
|
||||
|
||||
UTF8_STRING = XInternAtom(dpy, "UTF8_STRING", False);
|
||||
XROOTPMAP_ID = XInternAtom(dpy, "_XROOTPMAP_ID", False);
|
||||
WM_STATE = XInternAtom(dpy, "WM_STATE", False);
|
||||
WM_CLASS = XInternAtom(dpy, "WM_CLASS", False);
|
||||
WM_NAME = XInternAtom(dpy, "WM_NAME", False);
|
||||
WM_DELETE_WINDOW = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
|
||||
WM_CHANGE_STATE = XInternAtom(dpy, "WM_CHANGE_STATE", False);
|
||||
WM_WINDOW_ROLE = XInternAtom(dpy, "WM_WINDOW_ROLE", False);
|
||||
|
||||
WM_PROTOCOLS = XInternAtom(dpy, "WM_PROTOCOLS", False);
|
||||
NET_WORKAREA = XInternAtom(dpy, "_NET_WORKAREA", False);
|
||||
NET_CLIENT_LIST = XInternAtom(dpy, "_NET_CLIENT_LIST", False);
|
||||
NET_CLIENT_LIST_STACKING = XInternAtom(dpy, "_NET_CLIENT_LIST_STACKING", False);
|
||||
NET_NUMBER_OF_DESKTOPS = XInternAtom(dpy, "_NET_NUMBER_OF_DESKTOPS", False);
|
||||
NET_CURRENT_DESKTOP = XInternAtom(dpy, "_NET_CURRENT_DESKTOP", False);
|
||||
NET_DESKTOP_NAMES = XInternAtom(dpy, "_NET_DESKTOP_NAMES", False);
|
||||
NET_ACTIVE_WINDOW = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False);
|
||||
NET_CLOSE_WINDOW = XInternAtom(dpy, "_NET_CLOSE_WINDOW", False);
|
||||
NET_SUPPORTED = XInternAtom(dpy, "_NET_SUPPORTED", False);
|
||||
NET_WM_DESKTOP = XInternAtom(dpy, "_NET_WM_DESKTOP", False);
|
||||
NET_SHOWING_DESKTOP = XInternAtom(dpy, "_NET_SHOWING_DESKTOP", False);
|
||||
|
||||
NET_WM_STATE = XInternAtom(dpy, "_NET_WM_STATE", False);
|
||||
NET_WM_STATE_MODAL = XInternAtom(dpy, "_NET_WM_STATE_MODAL", False);
|
||||
NET_WM_STATE_STICKY = XInternAtom(dpy, "_NET_WM_STATE_STICKY", False);
|
||||
NET_WM_STATE_MAXIMIZED_VERT = XInternAtom(dpy, "_NET_WM_STATE_MAXIMIZED_VERT", False);
|
||||
NET_WM_STATE_MAXIMIZED_HORZ = XInternAtom(dpy, "_NET_WM_STATE_MAXIMIZED_HORZ", False);
|
||||
NET_WM_STATE_SHADED = XInternAtom(dpy, "_NET_WM_STATE_SHADED", False);
|
||||
NET_WM_STATE_SKIP_TASKBAR = XInternAtom(dpy, "_NET_WM_STATE_SKIP_TASKBAR", False);
|
||||
NET_WM_STATE_SKIP_PAGER = XInternAtom(dpy, "_NET_WM_STATE_SKIP_PAGER", False);
|
||||
NET_WM_STATE_HIDDEN = XInternAtom(dpy, "_NET_WM_STATE_HIDDEN", False);
|
||||
NET_WM_STATE_FULLSCREEN = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
|
||||
NET_WM_STATE_ABOVE = XInternAtom(dpy, "_NET_WM_STATE_ABOVE", False);
|
||||
NET_WM_STATE_BELOW = XInternAtom(dpy, "_NET_WM_STATE_BELOW", False);
|
||||
NET_WM_STATE_STAYS_ON_TOP = XInternAtom(dpy, "_NET_WM_STATE_STAYS_ON_TOP", False);
|
||||
NET_WM_STATE_STAYS_ON_BOTTOM = XInternAtom(dpy, "_NET_WM_STATE_STAYS_ON_BOTTOM", False);
|
||||
NET_WM_STATE_DEMANDS_ATTENTION = XInternAtom(dpy, "_NET_WM_STATE_DEMANDS_ATTENTION", False);
|
||||
|
||||
NET_WM_WINDOW_TYPE = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False);
|
||||
NET_WM_WINDOW_TYPE_DESKTOP = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DESKTOP", False);
|
||||
NET_WM_WINDOW_TYPE_DOCK = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DOCK", False);
|
||||
MODERRO_WINDOW_TYPE_DOCK = XInternAtom(dpy, "_MODERRO_WINDOW_TYPE_DOCK", False);
|
||||
NET_WM_WINDOW_TYPE_TOOLBAR = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_TOOLBAR", False);
|
||||
NET_WM_WINDOW_TYPE_MENU = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_MENU", False);
|
||||
NET_WM_WINDOW_TYPE_UTILITY = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_UTILITY", False);
|
||||
NET_WM_WINDOW_TYPE_SPLASH = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_SPLASH", False);
|
||||
NET_WM_WINDOW_TYPE_DIALOG = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DIALOG", False);
|
||||
NET_WM_WINDOW_TYPE_DROPDOWN_MENU = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU", False);
|
||||
NET_WM_WINDOW_TYPE_POPUP_MENU = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_POPUP_MENU", False);
|
||||
NET_WM_WINDOW_TYPE_TOOLTIP = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_TOOLTIP", False);
|
||||
NET_WM_WINDOW_TYPE_NOTIFICATION = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_NOTIFICATION", False);
|
||||
NET_WM_WINDOW_TYPE_COMBO = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_COMBO", False);
|
||||
NET_WM_WINDOW_TYPE_DND = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_DND", False);
|
||||
NET_WM_WINDOW_TYPE_NORMAL = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE_NORMAL", False);
|
||||
|
||||
NET_WM_WINDOW_OPACITY = XInternAtom(dpy, "_NET_WM_WINDOW_OPACITY", False);
|
||||
NET_WM_NAME = XInternAtom(dpy, "_NET_WM_NAME", False);
|
||||
NET_WM_VISIBLE_NAME = XInternAtom(dpy, "_NET_WM_VISIBLE_NAME", False);
|
||||
NET_WM_STRUT = XInternAtom(dpy, "_NET_WM_STRUT", False);
|
||||
NET_WM_STRUT_PARTIAL = XInternAtom(dpy, "_NET_WM_STRUT_PARTIAL", False);
|
||||
NET_WM_ICON = XInternAtom(dpy, "_NET_WM_ICON", False);
|
||||
NET_WM_PID = XInternAtom(dpy, "_NET_WM_PID", False);
|
||||
}
|
||||
|
||||
int NETWM::setProperty(Window window, Atom atom, long offset, uchar *data, int nelem)
|
||||
{
|
||||
NETWM::checkInit();
|
||||
|
||||
return XChangeProperty(QX11Info::display(), window, atom, offset, 32, PropModeReplace, data, nelem);
|
||||
}
|
||||
|
||||
int NETWM::setPropertySkipTaskbar(Window window)
|
||||
{
|
||||
NETWM::checkInit();
|
||||
|
||||
Atom state[3];
|
||||
|
||||
state[0] = NETWM::NET_WM_STATE_SKIP_PAGER;
|
||||
state[1] = NETWM::NET_WM_STATE_SKIP_TASKBAR;
|
||||
state[2] = NETWM::NET_WM_STATE_STICKY;
|
||||
|
||||
return NETWM::setProperty(window, NETWM::NET_WM_STATE, XA_ATOM, (uchar *)&state, 3);
|
||||
}
|
||||
|
||||
int NETWM::setPropertyOnTop(Window window)
|
||||
{
|
||||
NETWM::checkInit();
|
||||
|
||||
Atom state[2];
|
||||
|
||||
state[0] = NETWM::NET_WM_STATE_ABOVE;
|
||||
state[1] = NETWM::NET_WM_STATE_STAYS_ON_TOP;
|
||||
|
||||
return NETWM::setProperty(window, NETWM::NET_WM_STATE, XA_ATOM, (uchar *)&state, 2);
|
||||
}
|
||||
|
||||
void* NETWM::property(Window win, Atom prop, Atom type, int *nitems, bool *ok)
|
||||
{
|
||||
NETWM::checkInit();
|
||||
|
||||
Atom type_ret;
|
||||
int format_ret;
|
||||
unsigned long items_ret;
|
||||
unsigned long after_ret;
|
||||
unsigned char *prop_data = 0;
|
||||
|
||||
if(XGetWindowProperty(QX11Info::display(),
|
||||
win,
|
||||
prop,
|
||||
0,
|
||||
0x7fffffff,
|
||||
False,
|
||||
type,
|
||||
&type_ret,
|
||||
&format_ret,
|
||||
&items_ret,
|
||||
&after_ret,
|
||||
&prop_data) != Success)
|
||||
{
|
||||
if(ok)
|
||||
*ok = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(nitems)
|
||||
*nitems = items_ret;
|
||||
|
||||
if(ok)
|
||||
*ok = true;
|
||||
|
||||
return prop_data;
|
||||
}
|
||||
|
||||
bool NETWM::climsg(Window win, long type, long l0, long l1, long l2, long l3, long l4)
|
||||
{
|
||||
NETWM::checkInit();
|
||||
|
||||
XClientMessageEvent xev;
|
||||
|
||||
xev.type = ClientMessage;
|
||||
xev.window = win;
|
||||
xev.message_type = type;
|
||||
xev.format = 32;
|
||||
xev.data.l[0] = l0;
|
||||
xev.data.l[1] = l1;
|
||||
xev.data.l[2] = l2;
|
||||
xev.data.l[3] = l3;
|
||||
xev.data.l[4] = l4;
|
||||
|
||||
return (XSendEvent(QX11Info::display(), QX11Info::appRootWindow(), False,
|
||||
(SubstructureNotifyMask | SubstructureRedirectMask),
|
||||
(XEvent *)&xev) == Success);
|
||||
}
|
||||
|
||||
bool NETWM::climsgwm(Window win, Atom type, Atom arg)
|
||||
{
|
||||
NETWM::checkInit();
|
||||
|
||||
XClientMessageEvent xev;
|
||||
|
||||
xev.type = ClientMessage;
|
||||
xev.window = win;
|
||||
xev.message_type = type;
|
||||
xev.format = 32;
|
||||
xev.data.l[0] = arg;
|
||||
xev.data.l[1] = CurrentTime;
|
||||
|
||||
return (XSendEvent(QX11Info::display(), win, False, 0L, (XEvent *)&xev) == Success);
|
||||
}
|
||||
|
||||
uint NETWM::netwmDesktopsNumber()
|
||||
{
|
||||
NETWM::checkInit();
|
||||
|
||||
uint desknum;
|
||||
quint32 *data;
|
||||
|
||||
data = (quint32 *)NETWM::property(QX11Info::appRootWindow(), NETWM::NET_NUMBER_OF_DESKTOPS, XA_CARDINAL, 0);
|
||||
|
||||
if(!data)
|
||||
return 0;
|
||||
|
||||
desknum = *data;
|
||||
XFree(data);
|
||||
|
||||
return desknum;
|
||||
}
|
||||
|
||||
uint NETWM::netwmCurrentDesktop()
|
||||
{
|
||||
NETWM::checkInit();
|
||||
|
||||
uint desk;
|
||||
quint32 *data;
|
||||
|
||||
data = (quint32 *)NETWM::property(QX11Info::appRootWindow(), NETWM::NET_CURRENT_DESKTOP, XA_CARDINAL, 0);
|
||||
|
||||
if(!data)
|
||||
return 0;
|
||||
|
||||
desk = *data;
|
||||
XFree(data);
|
||||
|
||||
return desk;
|
||||
}
|
||||
|
||||
qint64 NETWM::netwmPid(Window win)
|
||||
{
|
||||
NETWM::checkInit();
|
||||
|
||||
qint64 pid = -1;
|
||||
ulong *data;
|
||||
|
||||
data = (ulong *)NETWM::property(win, NETWM::NET_WM_PID, XA_CARDINAL, 0);
|
||||
|
||||
if(data)
|
||||
{
|
||||
pid = *data;
|
||||
XFree(data);
|
||||
}
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
bool NETWM::netwmActivateWindow(Window win)
|
||||
{
|
||||
NETWM::checkInit();
|
||||
|
||||
return NETWM::climsg(win, NETWM::NET_ACTIVE_WINDOW, 2, CurrentTime);
|
||||
}
|
||||
|
||||
QList<Window> NETWM::netwmWindowList()
|
||||
{
|
||||
NETWM::checkInit();
|
||||
|
||||
QList<Window> list;
|
||||
int num;
|
||||
|
||||
Window *win = reinterpret_cast<Window *>(NETWM::property(QX11Info::appRootWindow(), NETWM::NET_CLIENT_LIST, XA_WINDOW, &num));
|
||||
|
||||
if(!win)
|
||||
{
|
||||
qDebug("NETWM: Cannot get window list");
|
||||
return list;
|
||||
}
|
||||
|
||||
for(int i = 0;i < num;i++)
|
||||
list.append(win[i]);
|
||||
|
||||
XFree(win);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
int NETWM::netwmDesktop(Window win)
|
||||
{
|
||||
NETWM::checkInit();
|
||||
|
||||
int desk = 0;
|
||||
ulong *data;
|
||||
|
||||
data = (ulong *)NETWM::property(win, NETWM::NET_WM_DESKTOP, XA_CARDINAL, 0);
|
||||
|
||||
if(data)
|
||||
{
|
||||
desk = *data;
|
||||
XFree(data);
|
||||
}
|
||||
|
||||
return desk;
|
||||
}
|
||||
|
||||
NETWM::net_wm_state NETWM::netwmState(Window win)
|
||||
{
|
||||
NETWM::checkInit();
|
||||
|
||||
net_wm_state nws;
|
||||
Atom *state;
|
||||
int num3;
|
||||
|
||||
if(!(state = (Atom *)NETWM::property(win, NETWM::NET_WM_STATE, XA_ATOM, &num3)))
|
||||
return nws;
|
||||
|
||||
while(--num3 >= 0)
|
||||
{
|
||||
if(state[num3] == NETWM::NET_WM_STATE_MODAL)
|
||||
{
|
||||
DBG("NET_WM_STATE_MODAL\n");
|
||||
nws.modal = 1;
|
||||
}
|
||||
else if(state[num3] == NETWM::NET_WM_STATE_STICKY)
|
||||
{
|
||||
DBG("NET_WM_STATE_STICKY\n");
|
||||
nws.sticky = 1;
|
||||
}
|
||||
else if(state[num3] == NETWM::NET_WM_STATE_MAXIMIZED_VERT)
|
||||
{
|
||||
DBG("NET_WM_STATE_MAXIMIZED_VERT\n");
|
||||
nws.maximized_vert = 1;
|
||||
}
|
||||
else if(state[num3] == NETWM::NET_WM_STATE_MAXIMIZED_HORZ)
|
||||
{
|
||||
DBG("NET_WM_STATE_MAXIMIZED_HORZ\n");
|
||||
nws.maximized_horz = 1;
|
||||
}
|
||||
else if(state[num3] == NETWM::NET_WM_STATE_SHADED)
|
||||
{
|
||||
DBG("NET_WM_STATE_SHADED\n");
|
||||
nws.shaded = 1;
|
||||
}
|
||||
else if(state[num3] == NETWM::NET_WM_STATE_SKIP_TASKBAR)
|
||||
{
|
||||
DBG("NET_WM_STATE_SKIP_TASKBAR\n");
|
||||
nws.skip_taskbar = 1;
|
||||
}
|
||||
else if(state[num3] == NETWM::NET_WM_STATE_SKIP_PAGER)
|
||||
{
|
||||
DBG("NET_WM_STATE_SKIP_PAGER\n");
|
||||
nws.skip_pager = 1;
|
||||
}
|
||||
else if(state[num3] == NETWM::NET_WM_STATE_HIDDEN)
|
||||
{
|
||||
DBG("NET_WM_STATE_HIDDEN\n");
|
||||
nws.hidden = 1;
|
||||
}
|
||||
else if(state[num3] == NETWM::NET_WM_STATE_FULLSCREEN)
|
||||
{
|
||||
DBG("NET_WM_STATE_FULLSCREEN\n");
|
||||
nws.fullscreen = 1;
|
||||
}
|
||||
else if(state[num3] == NETWM::NET_WM_STATE_ABOVE)
|
||||
{
|
||||
DBG("NET_WM_STATE_ABOVE\n");
|
||||
nws.above = 1;
|
||||
}
|
||||
else if(state[num3] == NETWM::NET_WM_STATE_BELOW)
|
||||
{
|
||||
DBG("NET_WM_STATE_BELOW\n");
|
||||
nws.below = 1;
|
||||
}
|
||||
else if(state[num3] == NETWM::NET_WM_STATE_STAYS_ON_TOP)
|
||||
{
|
||||
DBG("NET_WM_STATE_STAYS_ON_TOP\n");
|
||||
nws.stays_on_top = 1;
|
||||
}
|
||||
else if(state[num3] == NETWM::NET_WM_STATE_STAYS_ON_BOTTOM)
|
||||
{
|
||||
DBG("NET_WM_STATE_STAYS_ON_BOTTOM\n");
|
||||
nws.stays_on_bottom = 1;
|
||||
}
|
||||
else if(state[num3] == NETWM::NET_WM_STATE_DEMANDS_ATTENTION)
|
||||
{
|
||||
DBG("NET_WM_STATE_DEMANDS_ATTENTION\n");
|
||||
nws.demands_attention = 1;
|
||||
}
|
||||
}
|
||||
|
||||
nws.valid = true;
|
||||
|
||||
XFree(state);
|
||||
|
||||
return nws;
|
||||
}
|
||||
|
||||
NETWM::net_wm_window_type NETWM::netwmWindowType(Window win)
|
||||
{
|
||||
NETWM::checkInit();
|
||||
|
||||
net_wm_window_type nwwt;
|
||||
Atom *state;
|
||||
int num3;
|
||||
bool ok;
|
||||
|
||||
|
||||
if(!(state = (Atom *)NETWM::property(win, NETWM::NET_WM_WINDOW_TYPE, XA_ATOM, &num3, &ok)))
|
||||
{
|
||||
if(ok)
|
||||
{
|
||||
nwwt.valid = true;
|
||||
nwwt.normal = 1;
|
||||
}
|
||||
|
||||
return nwwt;
|
||||
}
|
||||
|
||||
nwwt.valid = true;
|
||||
|
||||
while(--num3 >= 0)
|
||||
{
|
||||
if(state[num3] == NETWM::NET_WM_WINDOW_TYPE_DESKTOP)
|
||||
{
|
||||
DBG("NET_WM_WINDOW_TYPE_DESKTOP\n");
|
||||
nwwt.desktop = 1;
|
||||
}
|
||||
else if(state[num3] == NETWM::NET_WM_WINDOW_TYPE_DOCK)
|
||||
{
|
||||
DBG("NET_WM_WINDOW_TYPE_DOCK\n");
|
||||
nwwt.dock = 1;
|
||||
}
|
||||
else if(state[num3] == NETWM::NET_WM_WINDOW_TYPE_TOOLBAR)
|
||||
{
|
||||
DBG("NET_WM_WINDOW_TYPE_TOOLBAR\n");
|
||||
nwwt.toolbar = 1;
|
||||
}
|
||||
else if(state[num3] == NETWM::NET_WM_WINDOW_TYPE_MENU)
|
||||
{
|
||||
DBG("NET_WM_WINDOW_TYPE_MENU\n");
|
||||
nwwt.menu = 1;
|
||||
}
|
||||
else if(state[num3] == NETWM::NET_WM_WINDOW_TYPE_UTILITY)
|
||||
{
|
||||
DBG("NET_WM_WINDOW_TYPE_UTILITY\n");
|
||||
nwwt.utility = 1;
|
||||
}
|
||||
else if(state[num3] == NETWM::NET_WM_WINDOW_TYPE_SPLASH)
|
||||
{
|
||||
DBG("NET_WM_WINDOW_TYPE_SPLASH\n");
|
||||
nwwt.splash = 1;
|
||||
}
|
||||
else if(state[num3] == NETWM::NET_WM_WINDOW_TYPE_DIALOG)
|
||||
{
|
||||
DBG("NET_WM_WINDOW_TYPE_DIALOG\n");
|
||||
nwwt.dialog = 1;
|
||||
}
|
||||
else if(state[num3] == NETWM::NET_WM_WINDOW_TYPE_DROPDOWN_MENU)
|
||||
{
|
||||
DBG("NET_WM_WINDOW_TYPE_DROPDOWN_MENU\n");
|
||||
nwwt.dropdown = 1;
|
||||
}
|
||||
else if(state[num3] == NETWM::NET_WM_WINDOW_TYPE_POPUP_MENU)
|
||||
{
|
||||
DBG("NET_WM_WINDOW_TYPE_POPUP_MENU\n");
|
||||
nwwt.popup = 1;
|
||||
}
|
||||
else if(state[num3] == NETWM::NET_WM_WINDOW_TYPE_TOOLTIP)
|
||||
{
|
||||
DBG("NET_WM_WINDOW_TYPE_TOOLTIP\n");
|
||||
nwwt.tooltip = 1;
|
||||
}
|
||||
else if(state[num3] == NETWM::NET_WM_WINDOW_TYPE_NOTIFICATION)
|
||||
{
|
||||
DBG("NET_WM_WINDOW_TYPE_NOTIFICATION\n");
|
||||
nwwt.notification = 1;
|
||||
}
|
||||
else if(state[num3] == NETWM::NET_WM_WINDOW_TYPE_COMBO)
|
||||
{
|
||||
DBG("NET_WM_WINDOW_TYPE_COMBO\n");
|
||||
nwwt.combo = 1;
|
||||
}
|
||||
else if(state[num3] == NETWM::NET_WM_WINDOW_TYPE_DND)
|
||||
{
|
||||
DBG("NET_WM_WINDOW_TYPE_DND\n");
|
||||
nwwt.dnd = 1;
|
||||
}
|
||||
else if(state[num3] == NETWM::NET_WM_WINDOW_TYPE_NORMAL)
|
||||
{
|
||||
DBG("NET_WM_WINDOW_TYPE_NORMAL\n");
|
||||
nwwt.normal = 1;
|
||||
}
|
||||
}
|
||||
|
||||
XFree(state);
|
||||
|
||||
return nwwt;
|
||||
}
|
||||
|
||||
QString NETWM::icccmString(Window win, Atom atom)
|
||||
{
|
||||
NETWM::checkInit();
|
||||
|
||||
QString s;
|
||||
char *data;
|
||||
|
||||
if(!(data = (char *)NETWM::property(win, atom, XA_STRING)))
|
||||
return s;
|
||||
|
||||
s = QString::fromUtf8(data);
|
||||
|
||||
XFree(data);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
QString NETWM::icccmUtf8String(Window win, Atom atom)
|
||||
{
|
||||
NETWM::checkInit();
|
||||
|
||||
Atom type;
|
||||
int format;
|
||||
ulong nitems;
|
||||
ulong bytes_after;
|
||||
int result;
|
||||
uchar *tmp = 0;
|
||||
QString val;
|
||||
|
||||
type = None;
|
||||
|
||||
result = XGetWindowProperty(QX11Info::display(), win, atom, 0, LONG_MAX, False,
|
||||
NETWM::UTF8_STRING, &type, &format, &nitems,
|
||||
&bytes_after, &tmp);
|
||||
|
||||
if(result != Success || type == None || !tmp)
|
||||
return val;
|
||||
|
||||
if(type == NETWM::UTF8_STRING && format == 8 && nitems != 0)
|
||||
val = QString::fromUtf8(reinterpret_cast<char *>(tmp));
|
||||
|
||||
XFree(tmp);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
QString NETWM::icccmWindowRole(Window win)
|
||||
{
|
||||
NETWM::checkInit();
|
||||
|
||||
return NETWM::icccmString(win, NETWM::WM_WINDOW_ROLE);
|
||||
}
|
||||
|
||||
QStringList NETWM::icccmClass(Window win)
|
||||
{
|
||||
NETWM::checkInit();
|
||||
|
||||
QStringList l;
|
||||
char *data;
|
||||
|
||||
if(!(data = (char *)NETWM::property(win, NETWM::WM_CLASS, XA_STRING)))
|
||||
return l;
|
||||
|
||||
l.append(QString::fromUtf8(data));
|
||||
l.append(QString::fromUtf8(data+strlen(data)+1));
|
||||
|
||||
XFree(data);
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
QString NETWM::icccmName(Window win)
|
||||
{
|
||||
NETWM::checkInit();
|
||||
|
||||
return NETWM::icccmString(win, NETWM::WM_NAME);
|
||||
}
|
||||
|
||||
QStringList NETWM::icccmCommand(Window win)
|
||||
{
|
||||
NETWM::checkInit();
|
||||
|
||||
QStringList list;
|
||||
char **argv;
|
||||
int argc;
|
||||
|
||||
if(!XGetCommand(QX11Info::display(), win, &argv, &argc))
|
||||
return list;
|
||||
|
||||
for(int i = 0;i < argc;i++)
|
||||
list.append(argv[i]);
|
||||
|
||||
XFreeStringList(argv);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
#define MO_NETWM_OPAQUE 0xffffffff
|
||||
|
||||
void NETWM::transset(Window window, double d)
|
||||
{
|
||||
NETWM::checkInit();
|
||||
|
||||
Display *dpy = QX11Info::display();
|
||||
|
||||
uint opacity = (uint)(d * MO_NETWM_OPAQUE);
|
||||
|
||||
if(opacity == MO_NETWM_OPAQUE)
|
||||
XDeleteProperty(dpy, window, NETWM::NET_WM_WINDOW_OPACITY);
|
||||
else
|
||||
XChangeProperty(dpy, window, NETWM::NET_WM_WINDOW_OPACITY,
|
||||
XA_CARDINAL, 32, PropModeReplace, (uchar *)&opacity, 1L);
|
||||
|
||||
XSync(dpy, False);
|
||||
}
|
||||
|
||||
#if 0
|
||||
bool NETWM::isComposite()
|
||||
{
|
||||
int event_base, error_base;
|
||||
|
||||
Display *dpy = QX11Info::display();
|
||||
|
||||
// extension is not supported
|
||||
if(!XCompositeQueryExtension(dpy, &event_base, &error_base))
|
||||
{
|
||||
qDebug("NETWM: Composite extension is not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
// NETWM-compliant composite manager MUST set selection owner
|
||||
// of _NET_WM_CM_Sn
|
||||
Window owner = XGetSelectionOwner(dpy, XInternAtom(dpy, "_NET_WM_CM_S0", False));
|
||||
|
||||
return (owner != None);
|
||||
}
|
||||
#endif
|
||||
|
||||
void NETWM::checkInit()
|
||||
{
|
||||
if(!NETWM::WM_STATE)
|
||||
NETWM::init();
|
||||
}
|
188
thirdparty/libqnetwm/libqnetwm/netwm.h
vendored
Normal file
188
thirdparty/libqnetwm/libqnetwm/netwm.h
vendored
Normal file
@@ -0,0 +1,188 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2010 by Dmitry 'Krasu' Baryshev *
|
||||
* ksquirrel.iv@gmail.com *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef NETWM_H
|
||||
#define NETWM_H
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xatom.h>
|
||||
|
||||
#include "fixx11h.h"
|
||||
|
||||
#include <QStringList>
|
||||
#include <QString>
|
||||
#include <QList>
|
||||
|
||||
class NETWM
|
||||
{
|
||||
|
||||
public:
|
||||
struct net_wm_state
|
||||
{
|
||||
net_wm_state();
|
||||
|
||||
unsigned int modal : 1;
|
||||
unsigned int sticky : 1;
|
||||
unsigned int maximized_vert : 1;
|
||||
unsigned int maximized_horz : 1;
|
||||
unsigned int shaded : 1;
|
||||
unsigned int skip_taskbar : 1;
|
||||
unsigned int skip_pager : 1;
|
||||
unsigned int hidden : 1;
|
||||
unsigned int fullscreen : 1;
|
||||
unsigned int above : 1;
|
||||
unsigned int below : 1;
|
||||
unsigned int stays_on_top : 1;
|
||||
unsigned int stays_on_bottom : 1;
|
||||
unsigned int demands_attention : 1;
|
||||
bool valid;
|
||||
};
|
||||
|
||||
struct net_wm_window_type
|
||||
{
|
||||
net_wm_window_type();
|
||||
|
||||
unsigned int desktop : 1;
|
||||
unsigned int dock : 1;
|
||||
unsigned int toolbar : 1;
|
||||
unsigned int menu : 1;
|
||||
unsigned int utility : 1;
|
||||
unsigned int splash : 1;
|
||||
unsigned int dialog : 1;
|
||||
unsigned int dropdown : 1;
|
||||
unsigned int popup : 1;
|
||||
unsigned int tooltip : 1;
|
||||
unsigned int notification : 1;
|
||||
unsigned int combo : 1;
|
||||
unsigned int dnd : 1;
|
||||
unsigned int normal : 1;
|
||||
bool valid;
|
||||
};
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static void init();
|
||||
|
||||
static void transset(Window, double);
|
||||
|
||||
#if 0
|
||||
static bool isComposite();
|
||||
#endif
|
||||
|
||||
static int setProperty(Window, Atom, long, uchar *, int);
|
||||
|
||||
static int setPropertySkipTaskbar(Window);
|
||||
static int setPropertyOnTop(Window);
|
||||
|
||||
static void* property(Window win, Atom prop, Atom type, int *nitems = 0, bool *ok = 0);
|
||||
|
||||
static bool climsg(Window win, long type, long l0, long l1 = 0, long l2 = 0, long l3 = 0, long l4 = 0);
|
||||
static bool climsgwm(Window win, Atom type, Atom arg);
|
||||
|
||||
// NETWM helper functions
|
||||
static qint64 netwmPid(Window win);
|
||||
static QList<Window> netwmWindowList();
|
||||
static uint netwmDesktopsNumber();
|
||||
static uint netwmCurrentDesktop();
|
||||
static int netwmDesktop(Window win);
|
||||
static net_wm_state netwmState(Window win);
|
||||
static net_wm_window_type netwmWindowType(Window win);
|
||||
static bool netwmActivateWindow(Window win);
|
||||
|
||||
// ICCCM helper functions
|
||||
static QString icccmString(Window win, Atom atom);
|
||||
static QString icccmUtf8String(Window win, Atom atom);
|
||||
static QString icccmWindowRole(Window win);
|
||||
static QStringList icccmClass(Window win);
|
||||
static QString icccmName(Window win);
|
||||
static QStringList icccmCommand(Window win);
|
||||
|
||||
/*************************************************************************/
|
||||
/********************************* Atoms *********************************/
|
||||
/*************************************************************************/
|
||||
|
||||
static Atom UTF8_STRING;
|
||||
static Atom XROOTPMAP_ID;
|
||||
|
||||
static Atom WM_STATE;
|
||||
static Atom WM_CLASS;
|
||||
static Atom WM_NAME;
|
||||
static Atom WM_DELETE_WINDOW;
|
||||
static Atom WM_PROTOCOLS;
|
||||
static Atom WM_CHANGE_STATE;
|
||||
static Atom WM_WINDOW_ROLE;
|
||||
|
||||
static Atom NET_WORKAREA;
|
||||
static Atom NET_CLIENT_LIST;
|
||||
static Atom NET_CLIENT_LIST_STACKING;
|
||||
static Atom NET_NUMBER_OF_DESKTOPS;
|
||||
static Atom NET_CURRENT_DESKTOP;
|
||||
static Atom NET_DESKTOP_NAMES;
|
||||
static Atom NET_ACTIVE_WINDOW;
|
||||
static Atom NET_CLOSE_WINDOW;
|
||||
static Atom NET_SUPPORTED;
|
||||
static Atom NET_WM_DESKTOP;
|
||||
static Atom NET_SHOWING_DESKTOP;
|
||||
|
||||
static Atom NET_WM_STATE;
|
||||
static Atom NET_WM_STATE_MODAL;
|
||||
static Atom NET_WM_STATE_STICKY;
|
||||
static Atom NET_WM_STATE_MAXIMIZED_VERT;
|
||||
static Atom NET_WM_STATE_MAXIMIZED_HORZ;
|
||||
static Atom NET_WM_STATE_SHADED;
|
||||
static Atom NET_WM_STATE_SKIP_TASKBAR;
|
||||
static Atom NET_WM_STATE_SKIP_PAGER;
|
||||
static Atom NET_WM_STATE_HIDDEN;
|
||||
static Atom NET_WM_STATE_FULLSCREEN;
|
||||
static Atom NET_WM_STATE_ABOVE;
|
||||
static Atom NET_WM_STATE_BELOW;
|
||||
static Atom NET_WM_STATE_STAYS_ON_TOP;
|
||||
static Atom NET_WM_STATE_STAYS_ON_BOTTOM;
|
||||
static Atom NET_WM_STATE_DEMANDS_ATTENTION;
|
||||
|
||||
static Atom NET_WM_WINDOW_TYPE;
|
||||
static Atom NET_WM_WINDOW_TYPE_DESKTOP;
|
||||
static Atom NET_WM_WINDOW_TYPE_DOCK;
|
||||
static Atom MODERRO_WINDOW_TYPE_DOCK;
|
||||
static Atom NET_WM_WINDOW_TYPE_TOOLBAR;
|
||||
static Atom NET_WM_WINDOW_TYPE_MENU;
|
||||
static Atom NET_WM_WINDOW_TYPE_UTILITY;
|
||||
static Atom NET_WM_WINDOW_TYPE_SPLASH;
|
||||
static Atom NET_WM_WINDOW_TYPE_DIALOG;
|
||||
static Atom NET_WM_WINDOW_TYPE_DROPDOWN_MENU;
|
||||
static Atom NET_WM_WINDOW_TYPE_POPUP_MENU;
|
||||
static Atom NET_WM_WINDOW_TYPE_TOOLTIP;
|
||||
static Atom NET_WM_WINDOW_TYPE_NOTIFICATION;
|
||||
static Atom NET_WM_WINDOW_TYPE_COMBO;
|
||||
static Atom NET_WM_WINDOW_TYPE_DND;
|
||||
static Atom NET_WM_WINDOW_TYPE_NORMAL;
|
||||
static Atom NET_WM_WINDOW_OPACITY;
|
||||
static Atom NET_WM_NAME;
|
||||
static Atom NET_WM_VISIBLE_NAME;
|
||||
static Atom NET_WM_STRUT;
|
||||
static Atom NET_WM_STRUT_PARTIAL;
|
||||
static Atom NET_WM_ICON;
|
||||
static Atom NET_WM_PID;
|
||||
|
||||
private:
|
||||
static void checkInit();
|
||||
};
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user