diff --git a/src/core/mpris1.cpp b/src/core/mpris1.cpp index df86f4d20..d9d2bb56d 100644 --- a/src/core/mpris1.cpp +++ b/src/core/mpris1.cpp @@ -244,7 +244,7 @@ int Mpris1Player::GetCaps(Engine::State state) const { if (state == Engine::Playing && !(current_item->options() & PlaylistItem::PauseDisabled)) { caps |= CAN_PAUSE; } - if (state != Engine::Empty && current_item->Metadata().filetype() != Song::Type_Stream) { + if (state != Engine::Empty && !current_item->Metadata().is_stream()) { caps |= CAN_SEEK; } } diff --git a/src/core/song.cpp b/src/core/song.cpp index b923ce09a..d7bbea50e 100644 --- a/src/core/song.cpp +++ b/src/core/song.cpp @@ -1141,9 +1141,8 @@ TagLib::String QStringToTaglibString(const QString& s) { } bool Song::IsEditable() const { - return d->valid_ && !d->filename_.isNull() && - d->filetype_ != Type_Stream && d->filetype_ != Type_Unknown && - !has_cue(); + return d->valid_ && !d->filename_.isNull() && !is_stream() && + d->filetype_ != Type_Unknown && !has_cue(); } bool Song::Save() const { diff --git a/src/core/song.h b/src/core/song.h index 440ea99f7..b0995e0ba 100644 --- a/src/core/song.h +++ b/src/core/song.h @@ -205,6 +205,7 @@ class Song { uint ctime() const { return d->ctime_; } int filesize() const { return d->filesize_; } FileType filetype() const { return d->filetype_; } + bool is_stream() const { return d->filetype_ == Type_Stream; } const QString& art_automatic() const { return d->art_automatic_; } const QString& art_manual() const { return d->art_manual_; } diff --git a/src/library/libraryview.cpp b/src/library/libraryview.cpp index 819b4a8c8..b842c3569 100644 --- a/src/library/libraryview.cpp +++ b/src/library/libraryview.cpp @@ -324,7 +324,7 @@ void LibraryView::contextMenuEvent(QContextMenuEvent *e) { // TODO: check if custom plugin actions should be enabled / visible const int songs_selected = smart_playlists + smart_playlists_header + regular_elements; - const bool regular_elements_only = songs_selected == regular_elements; + const bool regular_elements_only = songs_selected == regular_elements && regular_elements > 0; const bool smart_playlists_only = songs_selected == smart_playlists + smart_playlists_header; const bool only_smart_playlist_selected = smart_playlists == 1 && songs_selected == 1; @@ -335,6 +335,7 @@ void LibraryView::contextMenuEvent(QContextMenuEvent *e) { add_to_playlist_enqueue_->setEnabled(songs_selected); // allow mixed smart playlists / regular elements selected + show_in_browser_->setVisible(!smart_playlists_only); edit_tracks_->setVisible(!smart_playlists_only && regular_editable > 1); // if neither edit_track not edit_tracks are available, we show disabled // edit_track element diff --git a/src/playlist/playlist.cpp b/src/playlist/playlist.cpp index f4a2c25d1..ef1ed4d24 100644 --- a/src/playlist/playlist.cpp +++ b/src/playlist/playlist.cpp @@ -1580,7 +1580,7 @@ void Playlist::InvalidateDeletedSongs() { PlaylistItemPtr item = items_[row]; Song song = item->Metadata(); - if(song.filetype() != Song::Type_Stream) { + if(!song.is_stream()) { bool exists = QFile::exists(song.filename()); if(!exists && !item->HasForegroundColor(kInvalidSongPriority)) { @@ -1604,9 +1604,9 @@ bool Playlist::ApplyValidityOnCurrentSong(const QUrl& url, bool valid) { Song current_song = current->Metadata(); // if validity has changed, reload the item - if(current_song.filetype() != Song::Type_Stream && - current_song.filename() == url.toLocalFile() && - current_song.is_valid() != QFile::exists(current_song.filename())) { + if(!current_song.is_stream() && + current_song.filename() == url.toLocalFile() && + current_song.is_valid() != QFile::exists(current_song.filename())) { ReloadItems(QList() << current_row()); } diff --git a/src/playlist/songplaylistitem.cpp b/src/playlist/songplaylistitem.cpp index 1602e7444..7a9d4dfd7 100644 --- a/src/playlist/songplaylistitem.cpp +++ b/src/playlist/songplaylistitem.cpp @@ -29,7 +29,7 @@ SongPlaylistItem::SongPlaylistItem(const QString& type) } SongPlaylistItem::SongPlaylistItem(const Song& song) - : PlaylistItem(song.filetype() == Song::Type_Stream ? "Stream" : "File"), + : PlaylistItem(song.is_stream() ? "Stream" : "File"), song_(song) { } diff --git a/src/remote/remote.cpp b/src/remote/remote.cpp index 2e253ba85..d70f4b758 100644 --- a/src/remote/remote.cpp +++ b/src/remote/remote.cpp @@ -129,8 +129,7 @@ xrme::State Remote::state() const { ret.can_go_next = active->next_row() != -1 || active->current_item_options() & PlaylistItem::ContainsMultipleTracks; ret.can_go_previous = active->previous_row() != -1; - ret.can_seek = current_item && - current_item->Metadata().filetype() != Song::Type_Stream; + ret.can_seek = current_item && !current_item->Metadata().is_stream(); switch (state) { case Engine::Playing: ret.playback_state = xrme::State::PlaybackState_Playing; break; diff --git a/src/scripting/python/song.sip b/src/scripting/python/song.sip index ae6df61a9..d54548d3a 100644 --- a/src/scripting/python/song.sip +++ b/src/scripting/python/song.sip @@ -69,7 +69,7 @@ marked in any of these ways. composer, track, disc, bpm, year, genre, comment, is_compilation, rating, playcount, skipcount, lastplayed, score, cue_path, has_cue, beginning_nanosec, end_nanosec, length_nanosec, bitrate, samplerate, directory_id, filename, - basefilename, mtime, ctime, filesize, filetype, art_automatic, art_manual, + basefilename, mtime, ctime, filesize, filetype, is_stream, art_automatic, art_manual, has_manually_unset_cover, has_embedded_cover, image, url, IsEditable, IsMetadataEqual @group Pretty getters: PrettyTitle, PrettyTitleWithArtist, PrettyLength, @@ -360,6 +360,12 @@ filetype() -> FileType The type of media file. @see: L{TextForFiletype} +%End + + bool is_stream() const; +%Docstring +is_stream() -> bool +True if this song represents a stream (a remote file) and false otherwise. %End QString art_automatic() const; diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index fad4161b6..84cf5b205 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -1100,24 +1100,32 @@ void MainWindow::PlaylistRightClick(const QPoint& global_pos, const QModelIndex& QModelIndexList selection = ui_->playlist->view()->selectionModel()->selection().indexes(); bool cue_selected = false; int editable = 0; + int streams = 0; int in_queue = 0; int not_in_queue = 0; foreach (const QModelIndex& index, selection) { if (index.column() != 0) continue; - if(playlists_->current()->item_at(index.row())->Metadata().has_cue()) { + PlaylistItemPtr item = playlists_->current()->item_at(index.row()); + if(item->Metadata().has_cue()) { cue_selected = true; - } else if (playlists_->current()->item_at(index.row())->Metadata().IsEditable()) { + } else if (item->Metadata().IsEditable()) { editable++; } + if(item->Metadata().is_stream()) { + streams++; + } + if (index.data(Playlist::Role_QueuePosition).toInt() == -1) not_in_queue ++; else in_queue ++; } + int all = not_in_queue + in_queue; + // this is available when we have one or many files and at least one of // those is not CUE related ui_->action_edit_track->setEnabled(editable); @@ -1129,6 +1137,9 @@ void MainWindow::PlaylistRightClick(const QPoint& global_pos, const QModelIndex& if(cue_selected) editable = 0; + // no 'show in browser' action if only streams are selected + playlist_open_in_browser_->setVisible(streams != all); + bool track_column = (index.column() == Playlist::Column_Track); ui_->action_renumber_tracks->setVisible(editable >= 2 && track_column); ui_->action_selection_set_value->setVisible(editable >= 2 && !track_column); diff --git a/tests/asxparser_test.cpp b/tests/asxparser_test.cpp index 460670f07..3676b262d 100644 --- a/tests/asxparser_test.cpp +++ b/tests/asxparser_test.cpp @@ -66,8 +66,8 @@ TEST_F(ASXParserTest, ParsesMoreThanOneTrackFromXML) { ASSERT_EQ(2, songs.length()); EXPECT_EQ("http://example.com/foo.mp3", songs[0].filename()); EXPECT_EQ("http://example.com/bar.mp3", songs[1].filename()); - EXPECT_EQ(Song::Type_Stream, songs[0].filetype()); - EXPECT_EQ(Song::Type_Stream, songs[1].filetype()); + EXPECT_TRUE(songs[0].is_stream()); + EXPECT_TRUE(songs[1].is_stream()); } TEST_F(ASXParserTest, ParsesBrokenXmlEntities) { diff --git a/tests/plsparser_test.cpp b/tests/plsparser_test.cpp index 5f26be91b..1815b1497 100644 --- a/tests/plsparser_test.cpp +++ b/tests/plsparser_test.cpp @@ -66,7 +66,7 @@ TEST_F(PLSParserTest, ParseSomaFM) { EXPECT_EQ("SomaFM: Groove Salad (#2 128k mp3): A nicely chilled plate of ambient beats and grooves.", songs[1].title()); EXPECT_EQ("SomaFM: Groove Salad (#3 128k mp3): A nicely chilled plate of ambient beats and grooves.", songs[2].title()); EXPECT_EQ(-1, songs[0].length_nanosec()); - EXPECT_EQ(Song::Type_Stream, songs[0].filetype()); + EXPECT_TRUE(songs[0].is_stream()); } TEST_F(PLSParserTest, ParseSomaFM2) { @@ -82,7 +82,7 @@ TEST_F(PLSParserTest, ParseSomaFM2) { EXPECT_EQ("SomaFM: Secret Agent (#2 128k mp3): The soundtrack for your stylish, mysterious, dangerous life. For Spies and PIs too!", songs[1].title()); EXPECT_EQ("SomaFM: Secret Agent (#3 128k mp3): The soundtrack for your stylish, mysterious, dangerous life. For Spies and PIs too!", songs[2].title()); EXPECT_EQ(-1, songs[0].length_nanosec()); - EXPECT_EQ(Song::Type_Stream, songs[0].filetype()); + EXPECT_TRUE(songs[0].is_stream()); } TEST_F(PLSParserTest, SaveAndLoad) { diff --git a/tests/xspfparser_test.cpp b/tests/xspfparser_test.cpp index d8ffdc8cb..d2e8dc623 100644 --- a/tests/xspfparser_test.cpp +++ b/tests/xspfparser_test.cpp @@ -71,8 +71,8 @@ TEST_F(XSPFParserTest, ParsesMoreThanOneTrackFromXML) { ASSERT_EQ(2, songs.length()); EXPECT_EQ("http://example.com/foo.mp3", songs[0].filename()); EXPECT_EQ("http://example.com/bar.mp3", songs[1].filename()); - EXPECT_EQ(Song::Type_Stream, songs[0].filetype()); - EXPECT_EQ(Song::Type_Stream, songs[1].filetype()); + EXPECT_TRUE(songs[0].is_stream()); + EXPECT_TRUE(songs[1].is_stream()); } TEST_F(XSPFParserTest, IgnoresInvalidLength) {