Add a "complete tags automatically" shortcut to the playlist context menu. Fixes issue #1532

This commit is contained in:
David Sansome 2011-03-06 14:07:41 +00:00
parent 99101c8442
commit c2445edad5
12 changed files with 207 additions and 28 deletions

View File

@ -302,5 +302,6 @@
<file>icons/22x22/network-server.png</file>
<file>icons/32x32/network-server.png</file>
<file>icons/48x48/network-server.png</file>
<file>providers/musicbrainz.png</file>
</qresource>
</RCC>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -57,7 +57,6 @@ TagFetcher::TagFetcher(QObject *parent)
}
TagFetcher::~TagFetcher() {
delete network_;
tp_Delete(pimp_);
}

View File

@ -64,8 +64,8 @@ EditTagDialog::EditTagDialog(QWidget* parent)
connect(tag_fetcher_, SIGNAL(FetchFinished(QString, SongList)),
results_dialog_, SLOT(FetchTagFinished(QString, SongList)),
Qt::QueuedConnection);
connect(results_dialog_, SIGNAL(SongChosen(QString, Song)),
SLOT(FetchTagSongChosen(QString, Song)));
connect(results_dialog_, SIGNAL(SongChosen(Song, Song)),
SLOT(FetchTagSongChosen(Song, Song)));
#endif
ui_->setupUi(this);
@ -708,7 +708,8 @@ void EditTagDialog::FetchTag() {
#endif
}
void EditTagDialog::FetchTagSongChosen(const QString& filename, const Song& new_metadata) {
void EditTagDialog::FetchTagSongChosen(const Song& original_song, const Song& new_metadata) {
const QString filename = original_song.filename();
// Find the song with this filename
for (int i=0 ; i<data_.count() ; ++i) {

View File

@ -75,7 +75,7 @@ private slots:
void SongRated(float rating);
void ResetPlayCounts();
void FetchTag();
void FetchTagSongChosen(const QString& filename, const Song& new_metadata);
void FetchTagSongChosen(const Song& original_song, const Song& new_metadata);
void ArtLoaded(quint64 id, const QImage& scaled, const QImage& original);

View File

@ -30,7 +30,7 @@
</widget>
<widget class="QTabWidget" name="tab_widget">
<property name="currentIndex">
<number>0</number>
<number>1</number>
</property>
<widget class="QWidget" name="summary_tab">
<attribute name="title">
@ -823,6 +823,16 @@
<property name="text">
<string>Complete tags automatically</string>
</property>
<property name="icon">
<iconset resource="../../data/data.qrc">
<normaloff>:/providers/musicbrainz.png</normaloff>:/providers/musicbrainz.png</iconset>
</property>
<property name="iconSize">
<size>
<width>38</width>
<height>22</height>
</size>
</property>
</widget>
</item>
</layout>

View File

@ -32,6 +32,7 @@
#include "core/player.h"
#include "core/songloader.h"
#include "core/stylesheetloader.h"
#include "core/tagfetcher.h"
#include "core/taskmanager.h"
#include "devices/devicemanager.h"
#include "devices/devicestatefiltermodel.h"
@ -78,6 +79,7 @@
#include "ui/qtsystemtrayicon.h"
#include "ui/settingsdialog.h"
#include "ui/systemtrayicon.h"
#include "ui/trackselectiondialog.h"
#include "ui/windows7thumbbar.h"
#include "version.h"
#include "widgets/errordialog.h"
@ -296,6 +298,7 @@ MainWindow::MainWindow(
ui_->action_full_library_scan->setIcon(IconLoader::Load("view-refresh"));
ui_->action_rain->setIcon(IconLoader::Load("weather-showers-scattered"));
// File view connections
connect(file_view_, SIGNAL(AddToPlaylist(QMimeData*)), SLOT(AddToPlaylist(QMimeData*)));
connect(file_view_, SIGNAL(PathChanged(QString)), SLOT(FilePathChanged(QString)));
@ -322,6 +325,7 @@ MainWindow::MainWindow(
connect(ui_->action_renumber_tracks, SIGNAL(triggered()), SLOT(RenumberTracks()));
connect(ui_->action_selection_set_value, SIGNAL(triggered()), SLOT(SelectionSetValue()));
connect(ui_->action_edit_value, SIGNAL(triggered()), SLOT(EditValue()));
connect(ui_->action_auto_complete_tags, SIGNAL(triggered()), SLOT(AutoCompleteTags()));
connect(ui_->action_configure, SIGNAL(triggered()), SLOT(OpenSettingsDialog()));
connect(ui_->action_about, SIGNAL(triggered()), SLOT(ShowAboutDialog()));
connect(ui_->action_about_qt, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
@ -471,6 +475,9 @@ MainWindow::MainWindow(
playlist_menu_->addAction(ui_->action_edit_value);
playlist_menu_->addAction(ui_->action_renumber_tracks);
playlist_menu_->addAction(ui_->action_selection_set_value);
#ifdef HAVE_LIBTUNEPIMP
playlist_menu_->addAction(ui_->action_auto_complete_tags);
#endif
playlist_menu_->addSeparator();
playlist_copy_to_library_ = playlist_menu_->addAction(IconLoader::Load("edit-copy"), tr("Copy to library..."), this, SLOT(PlaylistCopyToLibrary()));
playlist_move_to_library_ = playlist_menu_->addAction(IconLoader::Load("go-jump"), tr("Move to library..."), this, SLOT(PlaylistMoveToLibrary()));
@ -1108,6 +1115,8 @@ void MainWindow::PlaylistRightClick(const QPoint& global_pos, const QModelIndex&
// those is not CUE related
ui_->action_edit_track->setEnabled(editable);
ui_->action_edit_track->setVisible(editable);
ui_->action_auto_complete_tags->setEnabled(editable);
ui_->action_auto_complete_tags->setVisible(editable);
// the rest of the read / write actions work only when there are no CUEs
// involved
if(cue_selected)
@ -1871,3 +1880,47 @@ void MainWindow::Exit() {
}
qApp->quit();
}
void MainWindow::AutoCompleteTags() {
// Create the tag fetching stuff if it hasn't been already
if (!tag_fetcher_) {
tag_fetcher_.reset(new TagFetcher);
track_selection_dialog_.reset(new TrackSelectionDialog);
track_selection_dialog_->set_save_on_close(true);
connect(tag_fetcher_.get(), SIGNAL(FetchFinished(QString, SongList)),
track_selection_dialog_.get(), SLOT(FetchTagFinished(QString, SongList)),
Qt::QueuedConnection);
connect(track_selection_dialog_.get(), SIGNAL(accepted()),
SLOT(AutoCompleteTagsAccepted()));
}
// Get the selected songs and start fetching tags for them
SongList songs;
autocomplete_tag_items_.clear();
foreach (const QModelIndex& index,
ui_->playlist->view()->selectionModel()->selection().indexes()) {
if (index.column() != 0)
continue;
int row = playlists_->current()->proxy()->mapToSource(index).row();
PlaylistItemPtr item(playlists_->current()->item_at(row));
Song song = item->Metadata();
if (song.IsEditable()) {
songs << song;
autocomplete_tag_items_ << item;
tag_fetcher_->FetchFromFile(song.filename());
}
}
track_selection_dialog_->Init(songs);
track_selection_dialog_->show();
}
void MainWindow::AutoCompleteTagsAccepted() {
foreach (PlaylistItemPtr item, autocomplete_tag_items_) {
item->Reload();
}
// This is really lame but we don't know what rows have changed
ui_->playlist->view()->update();
}

View File

@ -66,7 +66,9 @@ class Song;
class SongInfoBase;
class SongInfoView;
class SystemTrayIcon;
class TagFetcher;
class TaskManager;
class TrackSelectionDialog;
class TranscodeDialog;
class VisualisationContainer;
class WiimotedevShortcuts;
@ -157,6 +159,8 @@ class MainWindow : public QMainWindow, public PlatformInterface {
void RenumberTracks();
void SelectionSetValue();
void EditValue();
void AutoCompleteTags();
void AutoCompleteTagsAccepted();
void PlaylistUndoRedoChanged(QAction* undo, QAction* redo);
void PlaylistCopyToLibrary();
@ -283,6 +287,9 @@ class MainWindow : public QMainWindow, public PlatformInterface {
boost::scoped_ptr<OrganiseDialog> organise_dialog_;
boost::scoped_ptr<QueueManager> queue_manager_;
boost::scoped_ptr<TagFetcher> tag_fetcher_;
boost::scoped_ptr<TrackSelectionDialog> track_selection_dialog_;
PlaylistItemList autocomplete_tag_items_;
#ifdef ENABLE_VISUALISATIONS
boost::scoped_ptr<VisualisationContainer> visualisation_;

View File

@ -390,7 +390,7 @@
<x>0</x>
<y>0</y>
<width>1131</width>
<height>25</height>
<height>23</height>
</rect>
</property>
<widget class="QMenu" name="menu_music">
@ -764,6 +764,18 @@
<string>Do a full library rescan</string>
</property>
</action>
<action name="action_auto_complete_tags">
<property name="icon">
<iconset resource="../../data/data.qrc">
<normaloff>:/providers/musicbrainz.png</normaloff>:/providers/musicbrainz.png</iconset>
</property>
<property name="text">
<string>Complete tags automatically...</string>
</property>
<property name="shortcut">
<string>Ctrl+T</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>

View File

@ -19,13 +19,16 @@
#include "trackselectiondialog.h"
#include <QFileInfo>
#include <QFutureWatcher>
#include <QPushButton>
#include <QShortcut>
#include <QtConcurrentRun>
#include <QtDebug>
TrackSelectionDialog::TrackSelectionDialog(QWidget *parent)
: QDialog(parent),
ui_(new Ui_TrackSelectionDialog)
ui_(new Ui_TrackSelectionDialog),
save_on_close_(false)
{
// Setup dialog window
ui_->setupUi(this);
@ -35,6 +38,7 @@ TrackSelectionDialog::TrackSelectionDialog(QWidget *parent)
SLOT(ResultSelected()));
ui_->splitter->setSizes(QList<int>() << 200 << width() - 200);
SetLoading(QString());
// Add the next/previous buttons
previous_button_ = new QPushButton(IconLoader::Load("go-previous"), tr("Previous"), this);
@ -188,17 +192,68 @@ void TrackSelectionDialog::ResultSelected() {
data_[song_row].selected_result_ = result_index;
}
void TrackSelectionDialog::SetLoading(const QString& message) {
const bool loading = !message.isEmpty();
ui_->loading_container->setVisible(loading);
ui_->button_box->setEnabled(!loading);
ui_->splitter->setEnabled(!loading);
ui_->loading_label->setText(message);
}
void TrackSelectionDialog::SaveData(const QList<Data>& data) {
for (int i=0 ; i<data.count() ; ++i) {
const Data& ref = data[i];
if (ref.pending_ || ref.results_.isEmpty() || ref.selected_result_ == -1)
continue;
const Song& new_metadata = ref.results_[ref.selected_result_];
Song copy(ref.original_song_);
copy.set_title(new_metadata.title());
copy.set_artist(new_metadata.artist());
copy.set_album(new_metadata.album());
copy.set_track(new_metadata.track());
copy.Save();
}
}
void TrackSelectionDialog::accept() {
if (save_on_close_) {
SetLoading(tr("Saving tracks") + "...");
// Save tags in the background
QFuture<void> future = QtConcurrent::run(&TrackSelectionDialog::SaveData, data_);
QFutureWatcher<void>* watcher = new QFutureWatcher<void>(this);
watcher->setFuture(future);
connect(watcher, SIGNAL(finished()), SLOT(AcceptFinished()));
return;
}
QDialog::accept();
foreach (const Data& data, data_) {
if (data.pending_ || data.results_.isEmpty() || data.selected_result_ == -1)
continue;
emit SongChosen(data.original_song_.filename(), data.results_[data.selected_result_]);
const Song& new_metadata = data.results_[data.selected_result_];
emit SongChosen(data.original_song_, new_metadata);
}
}
void TrackSelectionDialog::AcceptFinished() {
QFutureWatcher<void>* watcher = dynamic_cast<QFutureWatcher<void>*>(sender());
if (!watcher)
return;
watcher->deleteLater();
SetLoading(QString());
QDialog::accept();
}
void TrackSelectionDialog::NextSong() {
int row = (ui_->song_list->currentRow() + 1) % ui_->song_list->count();
ui_->song_list->setCurrentRow(row);

View File

@ -32,6 +32,8 @@ public:
TrackSelectionDialog(QWidget *parent = 0);
~TrackSelectionDialog();
void set_save_on_close(bool save_on_close) { save_on_close_ = save_on_close; }
void Init(const SongList& songs);
public slots:
@ -41,7 +43,7 @@ public slots:
void accept();
signals:
void SongChosen(const QString& filename, const Song& song);
void SongChosen(const Song& original_song, const Song& new_metadata);
private slots:
void UpdateStack();
@ -50,10 +52,7 @@ private slots:
void PreviousSong();
void ResultSelected();
private:
void AddDivider(const QString& text, QTreeWidget* parent) const;
void AddSong(const Song& song, int result_index, QTreeWidget* parent) const;
void AcceptFinished();
private:
Ui_TrackSelectionDialog* ui_;
@ -67,10 +66,19 @@ private:
int selected_result_;
};
void AddDivider(const QString& text, QTreeWidget* parent) const;
void AddSong(const Song& song, int result_index, QTreeWidget* parent) const;
void SetLoading(const QString& message);
static void SaveData(const QList<Data>& data);
private:
QList<Data> data_;
QPushButton* previous_button_;
QPushButton* next_button_;
bool save_on_close_;
};
#endif // TRACKSELECTIONDIALOG_H

View File

@ -221,20 +221,53 @@
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="button_box">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QWidget" name="loading_container" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="BusyIndicator" name="label_6">
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="loading_label">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="button_box">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>