Basic tag editing
This commit is contained in:
parent
e0bb24af07
commit
4108dc7c73
4
TODO
4
TODO
|
@ -3,11 +3,13 @@
|
|||
- Nice error messages
|
||||
- Automatically install xine plugins
|
||||
- Copy to library, move to library
|
||||
- Edit tags in the playlist
|
||||
- Global shortcut keys
|
||||
- Database versioning
|
||||
- Clicking play plays selected item
|
||||
|
||||
- Edit tags in playlist view
|
||||
- Watch subdirectories in library
|
||||
|
||||
Long-term:
|
||||
- iPod
|
||||
|
||||
|
|
|
@ -49,5 +49,6 @@
|
|||
<file>last.fm/user_purple.png</file>
|
||||
<file>list-remove.png</file>
|
||||
<file>clear-list.png</file>
|
||||
<file>edit-track.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 353 B |
|
@ -0,0 +1,106 @@
|
|||
#include "edittagdialog.h"
|
||||
#include "ui_edittagdialog.h"
|
||||
|
||||
#include <QtDebug>
|
||||
|
||||
EditTagDialog::EditTagDialog(QWidget* parent)
|
||||
: QDialog(parent)
|
||||
{
|
||||
ui_.setupUi(this);
|
||||
|
||||
static const char* kHintText = "[click to edit]";
|
||||
ui_.album->SetHint(kHintText);
|
||||
ui_.artist->SetHint(kHintText);
|
||||
ui_.genre->SetHint(kHintText);
|
||||
}
|
||||
|
||||
bool EditTagDialog::SetSongs(const SongList &s) {
|
||||
SongList songs;
|
||||
|
||||
foreach (const Song& song, s) {
|
||||
if (song.IsEditable())
|
||||
songs << song;
|
||||
}
|
||||
songs_ = songs;
|
||||
|
||||
// Don't allow editing of fields that don't make sense for multiple items
|
||||
ui_.title->setEnabled(songs.count() == 1);
|
||||
ui_.track->setEnabled(songs.count() == 1);
|
||||
ui_.comment->setEnabled(songs.count() == 1);
|
||||
|
||||
if (songs.count() == 0)
|
||||
return false;
|
||||
else if (songs.count() == 1) {
|
||||
const Song& song = songs[0];
|
||||
|
||||
ui_.title->setText(song.title());
|
||||
ui_.artist->setText(song.artist());
|
||||
ui_.album->setText(song.album());
|
||||
ui_.genre->setText(song.genre());
|
||||
ui_.year->setValue(song.year());
|
||||
ui_.track->setValue(song.track());
|
||||
ui_.comment->setPlainText(song.comment());
|
||||
|
||||
ui_.filename->setText(song.filename());
|
||||
} else {
|
||||
// Find any fields that are common to all items
|
||||
|
||||
ui_.title->clear();
|
||||
ui_.track->clear();
|
||||
ui_.comment->clear();
|
||||
|
||||
QString artist(songs[0].artist());
|
||||
QString album(songs[0].album());
|
||||
QString genre(songs[0].genre());
|
||||
int year = songs[0].year();
|
||||
|
||||
foreach (const Song& song, songs) {
|
||||
if (artist != song.artist())
|
||||
artist = QString::null;
|
||||
if (album != song.album())
|
||||
album = QString::null;
|
||||
if (genre != song.genre())
|
||||
genre = QString::null;
|
||||
if (year != song.year())
|
||||
year = -1;
|
||||
}
|
||||
|
||||
ui_.artist->setText(artist);
|
||||
ui_.album->setText(album);
|
||||
ui_.genre->setText(genre);
|
||||
ui_.year->setValue(year);
|
||||
|
||||
ui_.filename->setText("Editing " + QString::number(songs.count()) + " tracks");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void EditTagDialog::accept() {
|
||||
foreach (const Song& old, songs_) {
|
||||
Song song(old);
|
||||
|
||||
if (ui_.title->isEnabled() && !ui_.title->text().isEmpty())
|
||||
song.set_title(ui_.title->text());
|
||||
if (ui_.artist->isEnabled() && !ui_.artist->text().isEmpty())
|
||||
song.set_artist(ui_.artist->text());
|
||||
if (ui_.album->isEnabled() && !ui_.album->text().isEmpty())
|
||||
song.set_album(ui_.album->text());
|
||||
if (ui_.genre->isEnabled() && !ui_.genre->text().isEmpty())
|
||||
song.set_genre(ui_.genre->text());
|
||||
|
||||
if (ui_.year->isEnabled())
|
||||
song.set_year(ui_.year->value());
|
||||
if (ui_.track->isEnabled())
|
||||
song.set_track(ui_.track->value());
|
||||
|
||||
if (ui_.comment->isEnabled())
|
||||
song.set_comment(ui_.comment->toPlainText());
|
||||
|
||||
song.Save();
|
||||
|
||||
emit SongEdited(old, song);
|
||||
}
|
||||
|
||||
QDialog::accept();
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
#ifndef EDITTAGDIALOG_H
|
||||
#define EDITTAGDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
#include "ui_edittagdialog.h"
|
||||
#include "song.h"
|
||||
|
||||
class EditTagDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
EditTagDialog(QWidget* parent = 0);
|
||||
|
||||
bool SetSongs(const SongList& songs);
|
||||
|
||||
public slots:
|
||||
void accept();
|
||||
|
||||
signals:
|
||||
void SongEdited(const Song& old_song, const Song& new_song);
|
||||
|
||||
private:
|
||||
Ui::EditTagDialog ui_;
|
||||
|
||||
SongList songs_;
|
||||
};
|
||||
|
||||
#endif // EDITTAGDIALOG_H
|
|
@ -0,0 +1,206 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>EditTagDialog</class>
|
||||
<widget class="QDialog" name="EditTagDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>602</width>
|
||||
<height>290</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Edit track information</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<property name="horizontalSpacing">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="verticalSpacing">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Title</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="title"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Album</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="LineEdit" name="album"/>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Artist</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="LineEdit" name="artist"/>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Genre</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="LineEdit" name="genre"/>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Track</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="track">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Year</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="year">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Comment</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QPlainTextEdit" name="comment"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="filename">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">QLineEdit {
|
||||
background-color: transparent;
|
||||
}</string>
|
||||
</property>
|
||||
<property name="frame">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<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>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>LineEdit</class>
|
||||
<extends>QLineEdit</extends>
|
||||
<header>lineedit.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>EditTagDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>EditTagDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
|
@ -0,0 +1,36 @@
|
|||
#include "lineedit.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QPaintEvent>
|
||||
|
||||
LineEdit::LineEdit(QWidget* parent)
|
||||
: QLineEdit(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void LineEdit::SetHint(const QString& hint) {
|
||||
hint_ = hint;
|
||||
update();
|
||||
}
|
||||
|
||||
void LineEdit::paintEvent(QPaintEvent* e) {
|
||||
QLineEdit::paintEvent(e);
|
||||
|
||||
if (!hasFocus() && displayText().isEmpty() && !hint_.isEmpty()) {
|
||||
QPainter p(this);
|
||||
|
||||
QFont font;
|
||||
font.setItalic(true);
|
||||
font.setPointSize(font.pointSize()-1);
|
||||
|
||||
QFontMetrics m(font);
|
||||
const int kBorder = (height() - m.height()) / 2;
|
||||
|
||||
p.setPen(palette().color(QPalette::Disabled, QPalette::Text));
|
||||
p.setFont(font);
|
||||
|
||||
QRect r(rect().topLeft() + QPoint(kBorder + 5, kBorder),
|
||||
rect().bottomRight() - QPoint(kBorder, kBorder));
|
||||
p.drawText(r, Qt::AlignLeft | Qt::AlignVCenter, hint_);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
#ifndef LINEEDIT_H
|
||||
#define LINEEDIT_H
|
||||
|
||||
#include <QLineEdit>
|
||||
|
||||
class LineEdit : public QLineEdit {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString hint READ GetHint WRITE SetHint);
|
||||
|
||||
public:
|
||||
LineEdit(QWidget* parent = 0);
|
||||
|
||||
QString GetHint() const { return hint_; }
|
||||
void SetHint(const QString& hint);
|
||||
|
||||
void paintEvent(QPaintEvent* e);
|
||||
|
||||
private:
|
||||
QString hint_;
|
||||
};
|
||||
|
||||
#endif // LINEEDIT_H
|
|
@ -10,6 +10,7 @@
|
|||
#include "lastfmservice.h"
|
||||
#include "osd.h"
|
||||
#include "trackslider.h"
|
||||
#include "edittagdialog.h"
|
||||
|
||||
#include "qxtglobalshortcut.h"
|
||||
|
||||
|
@ -34,6 +35,7 @@ MainWindow::MainWindow(QWidget *parent)
|
|||
tray_icon_(new SystemTrayIcon(this)),
|
||||
osd_(new OSD(tray_icon_, this)),
|
||||
track_slider_(new TrackSlider(this)),
|
||||
edit_tag_dialog_(new EditTagDialog(this)),
|
||||
radio_model_(new RadioModel(this)),
|
||||
playlist_(new Playlist(this)),
|
||||
player_(new Player(playlist_, radio_model_->GetLastFMService(), this)),
|
||||
|
@ -84,6 +86,7 @@ MainWindow::MainWindow(QWidget *parent)
|
|||
connect(ui_.action_ban, SIGNAL(triggered()), radio_model_->GetLastFMService(), SLOT(Ban()));
|
||||
connect(ui_.action_love, SIGNAL(triggered()), SLOT(Love()));
|
||||
connect(ui_.action_clear_playlist, SIGNAL(triggered()), playlist_, SLOT(Clear()));
|
||||
connect(ui_.action_edit_track, SIGNAL(triggered()), SLOT(EditTracks()));
|
||||
|
||||
// Give actions to buttons
|
||||
ui_.forward_button->setDefaultAction(ui_.action_next_track);
|
||||
|
@ -171,6 +174,7 @@ MainWindow::MainWindow(QWidget *parent)
|
|||
playlist_play_pause_ = playlist_menu_->addAction("Play", this, SLOT(PlaylistPlay()));
|
||||
playlist_menu_->addAction(ui_.action_stop);
|
||||
playlist_stop_after_ = playlist_menu_->addAction(QIcon(":media-playback-stop.png"), "Stop after this track", this, SLOT(PlaylistStopAfter()));
|
||||
playlist_menu_->addAction(ui_.action_edit_track);
|
||||
playlist_menu_->addSeparator();
|
||||
playlist_menu_->addAction(ui_.action_clear_playlist);
|
||||
|
||||
|
@ -437,6 +441,19 @@ void MainWindow::PlaylistRightClick(const QPoint& global_pos, const QModelIndex&
|
|||
playlist_play_pause_->setEnabled(index.isValid());
|
||||
playlist_stop_after_->setEnabled(index.isValid());
|
||||
|
||||
// Are any of the selected songs editable?
|
||||
bool editable = false;
|
||||
foreach (const QModelIndex& index,
|
||||
ui_.playlist->selectionModel()->selection().indexes()) {
|
||||
if (index.column() != 0)
|
||||
continue;
|
||||
if (playlist_->item_at(index.row())->Metadata().IsEditable()) {
|
||||
editable = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ui_.action_edit_track->setEnabled(editable);
|
||||
|
||||
playlist_menu_->popup(global_pos);
|
||||
}
|
||||
|
||||
|
@ -451,3 +468,26 @@ void MainWindow::PlaylistPlay() {
|
|||
void MainWindow::PlaylistStopAfter() {
|
||||
playlist_->StopAfter(playlist_menu_index_.row());
|
||||
}
|
||||
|
||||
void MainWindow::EditTracks() {
|
||||
SongList songs;
|
||||
QList<int> rows;
|
||||
|
||||
foreach (const QModelIndex& index,
|
||||
ui_.playlist->selectionModel()->selection().indexes()) {
|
||||
if (index.column() != 0)
|
||||
continue;
|
||||
Song song = playlist_->item_at(index.row())->Metadata();
|
||||
|
||||
if (song.IsEditable()) {
|
||||
songs << song;
|
||||
rows << index.row();
|
||||
}
|
||||
}
|
||||
|
||||
edit_tag_dialog_->SetSongs(songs);
|
||||
if (edit_tag_dialog_->exec() == QDialog::Rejected)
|
||||
return;
|
||||
|
||||
playlist_->ReloadItems(rows);
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ class Song;
|
|||
class RadioItem;
|
||||
class OSD;
|
||||
class TrackSlider;
|
||||
class EditTagDialog;
|
||||
|
||||
class QSortFilterProxyModel;
|
||||
class SystemTrayIcon;
|
||||
|
@ -44,6 +45,7 @@ class MainWindow : public QMainWindow {
|
|||
void PlaylistRightClick(const QPoint& global_pos, const QModelIndex& index);
|
||||
void PlaylistPlay();
|
||||
void PlaylistStopAfter();
|
||||
void EditTracks();
|
||||
|
||||
void PlayIndex(const QModelIndex& index);
|
||||
void StopAfterCurrent();
|
||||
|
@ -72,6 +74,7 @@ class MainWindow : public QMainWindow {
|
|||
SystemTrayIcon* tray_icon_;
|
||||
OSD* osd_;
|
||||
TrackSlider* track_slider_;
|
||||
EditTagDialog* edit_tag_dialog_;
|
||||
|
||||
RadioModel* radio_model_;
|
||||
Playlist* playlist_;
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
<string>Clementine</string>
|
||||
</property>
|
||||
<property name="windowIcon">
|
||||
<iconset resource="../data/data.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/icon.png</normaloff>:/icon.png</iconset>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralWidget">
|
||||
|
@ -294,7 +294,7 @@
|
|||
<item>
|
||||
<widget class="QToolButton" name="library_filter_clear">
|
||||
<property name="icon">
|
||||
<iconset resource="../data/data.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/clear.png</normaloff>:/clear.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
|
@ -314,7 +314,7 @@
|
|||
<item>
|
||||
<widget class="QToolButton" name="library_options">
|
||||
<property name="icon">
|
||||
<iconset resource="../data/data.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/configure.png</normaloff>:/configure.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
|
@ -430,7 +430,7 @@
|
|||
</widget>
|
||||
<action name="action_previous_track">
|
||||
<property name="icon">
|
||||
<iconset resource="../data/data.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/media-skip-backward.png</normaloff>:/media-skip-backward.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
|
@ -439,7 +439,7 @@
|
|||
</action>
|
||||
<action name="action_play_pause">
|
||||
<property name="icon">
|
||||
<iconset resource="../data/data.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/media-playback-start.png</normaloff>:/media-playback-start.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
|
@ -451,7 +451,7 @@
|
|||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../data/data.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/media-playback-stop.png</normaloff>:/media-playback-stop.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
|
@ -460,7 +460,7 @@
|
|||
</action>
|
||||
<action name="action_next_track">
|
||||
<property name="icon">
|
||||
<iconset resource="../data/data.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/media-skip-forward.png</normaloff>:/media-skip-forward.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
|
@ -469,7 +469,7 @@
|
|||
</action>
|
||||
<action name="action_quit">
|
||||
<property name="icon">
|
||||
<iconset resource="../data/data.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/exit.png</normaloff>:/exit.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
|
@ -481,7 +481,7 @@
|
|||
</action>
|
||||
<action name="action_stop_after_this_track">
|
||||
<property name="icon">
|
||||
<iconset resource="../data/data.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/media-playback-stop.png</normaloff>:/media-playback-stop.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
|
@ -547,7 +547,7 @@
|
|||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../data/data.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/last.fm/love.png</normaloff>:/last.fm/love.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
|
@ -559,7 +559,7 @@
|
|||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../data/data.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/last.fm/ban.png</normaloff>:/last.fm/ban.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
|
@ -568,7 +568,7 @@
|
|||
</action>
|
||||
<action name="action_clear_playlist">
|
||||
<property name="icon">
|
||||
<iconset resource="../data/data.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/clear-list.png</normaloff>:/clear-list.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
|
@ -578,6 +578,15 @@
|
|||
<string>Clear playlist</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_edit_track">
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normaloff>:/edit-track.png</normaloff>:/edit-track.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Edit track information...</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<customwidgets>
|
||||
|
@ -614,8 +623,6 @@
|
|||
<header>radioview.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="../data/data.qrc"/>
|
||||
</resources>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
|
@ -502,3 +502,10 @@ void Playlist::Clear() {
|
|||
items_.clear();
|
||||
reset();
|
||||
}
|
||||
|
||||
void Playlist::ReloadItems(const QList<int>& rows) {
|
||||
foreach (int row, rows) {
|
||||
item_at(row)->Reload();
|
||||
emit dataChanged(index(row, 0), index(row, ColumnCount-1));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,6 +75,7 @@ class Playlist : public QAbstractListModel {
|
|||
QModelIndex InsertRadioStations(const QList<RadioItem*>& items, int after = -1);
|
||||
QModelIndex InsertPaths(QList<QUrl> urls, int after = -1);
|
||||
void StopAfter(int row);
|
||||
void ReloadItems(const QList<int>& rows);
|
||||
|
||||
// QAbstractListModel
|
||||
int rowCount(const QModelIndex& = QModelIndex()) const { return items_.count(); }
|
||||
|
|
|
@ -37,6 +37,7 @@ class PlaylistItem {
|
|||
|
||||
virtual void Save(QSettings& settings) const = 0;
|
||||
virtual void Restore(const QSettings& settings) = 0;
|
||||
virtual void Reload() {}
|
||||
|
||||
virtual Song Metadata() const = 0;
|
||||
|
||||
|
|
18
src/song.cpp
18
src/song.cpp
|
@ -72,7 +72,7 @@ void Song::InitFromFile(const QString& filename, int directory_id) {
|
|||
d->filename_ = filename;
|
||||
d->directory_id_ = directory_id;
|
||||
|
||||
TagLib::FileRef fileref = TagLib::FileRef(QFile::encodeName(filename).constData());
|
||||
TagLib::FileRef fileref(QFile::encodeName(filename).constData());
|
||||
|
||||
if( fileref.isNull() )
|
||||
return;
|
||||
|
@ -301,3 +301,19 @@ bool Song::IsMetadataEqual(const Song& other) const {
|
|||
d->bitrate_ == other.d->bitrate_ &&
|
||||
d->samplerate_ == other.d->samplerate_;
|
||||
}
|
||||
|
||||
bool Song::Save() const {
|
||||
if (d->filename_.isNull())
|
||||
return false;
|
||||
|
||||
TagLib::FileRef ref(QFile::encodeName(d->filename_).constData());
|
||||
ref.tag()->setTitle(d->title_.toUtf8().constData());
|
||||
ref.tag()->setArtist(d->artist_.toUtf8().constData());
|
||||
ref.tag()->setAlbum(d->album_.toUtf8().constData());
|
||||
ref.tag()->setGenre(d->genre_.toUtf8().constData());
|
||||
ref.tag()->setComment(d->comment_.toUtf8().constData());
|
||||
ref.tag()->setYear(d->year_);
|
||||
ref.tag()->setTrack(d->track_);
|
||||
|
||||
return ref.save();
|
||||
}
|
||||
|
|
23
src/song.h
23
src/song.h
|
@ -92,8 +92,29 @@ class Song {
|
|||
QString PrettyLength() const;
|
||||
|
||||
// Setters
|
||||
bool IsEditable() const { return d->valid_ && !d->filename_.isNull(); }
|
||||
bool Save() const;
|
||||
|
||||
void set_id(int id) { d->id_ = id; }
|
||||
void set_title(const QString& title) { d->title_ = title; }
|
||||
void set_title(const QString& v) { d->title_ = v; }
|
||||
|
||||
void set_album(const QString& v) { d->album_ = v; }
|
||||
void set_artist(const QString& v) { d->artist_ = v; }
|
||||
void set_albumartist(const QString& v) { d->albumartist_ = v; }
|
||||
void set_composer(const QString& v) { d->composer_ = v; }
|
||||
void set_track(int v) { d->track_ = v; }
|
||||
void set_disc(int v) { d->disc_ = v; }
|
||||
void set_bpm(float v) { d->bpm_ = v; }
|
||||
void set_year(int v) { d->year_ = v; }
|
||||
void set_genre(const QString& v) { d->genre_ = v; }
|
||||
void set_comment(const QString& v) { d->comment_ = v; }
|
||||
void set_compilation(bool v) { d->compilation_ = v; }
|
||||
void set_length(int v) { d->length_ = v; }
|
||||
void set_bitrate(int v) { d->bitrate_ = v; }
|
||||
void set_samplerate(int v) { d->samplerate_ = v; }
|
||||
void set_mtime(int v) { d->mtime_ = v; }
|
||||
void set_ctime(int v) { d->ctime_ = v; }
|
||||
void set_filesize(int v) { d->filesize_ = v; }
|
||||
|
||||
// Comparison functions
|
||||
bool IsMetadataEqual(const Song& other) const;
|
||||
|
|
|
@ -29,3 +29,7 @@ QUrl SongPlaylistItem::Url() {
|
|||
ret.setHost("localhost");
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SongPlaylistItem::Reload() {
|
||||
song_.InitFromFile(song_.filename(), song_.directory_id());
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ class SongPlaylistItem : public PlaylistItem {
|
|||
|
||||
void Save(QSettings& settings) const;
|
||||
void Restore(const QSettings& settings);
|
||||
void Reload();
|
||||
|
||||
Song Metadata() const { return song_; }
|
||||
|
||||
|
|
11
src/src.pro
11
src/src.pro
|
@ -45,7 +45,9 @@ SOURCES += main.cpp \
|
|||
radioview.cpp \
|
||||
lastfmstationdialog.cpp \
|
||||
osd.cpp \
|
||||
trackslider.cpp
|
||||
trackslider.cpp \
|
||||
edittagdialog.cpp \
|
||||
lineedit.cpp
|
||||
HEADERS += mainwindow.h \
|
||||
player.h \
|
||||
library.h \
|
||||
|
@ -91,14 +93,17 @@ HEADERS += mainwindow.h \
|
|||
lastfmstationdialog.h \
|
||||
../3rdparty/qxt/keymapper_x11.h \
|
||||
osd.h \
|
||||
trackslider.h
|
||||
trackslider.h \
|
||||
edittagdialog.h \
|
||||
lineedit.h
|
||||
FORMS += mainwindow.ui \
|
||||
libraryconfig.ui \
|
||||
fileview.ui \
|
||||
lastfmconfig.ui \
|
||||
radioloadingindicator.ui \
|
||||
lastfmstationdialog.ui \
|
||||
trackslider.ui
|
||||
trackslider.ui \
|
||||
edittagdialog.ui
|
||||
RESOURCES += ../data/data.qrc
|
||||
OTHER_FILES += ../data/schema.sql \
|
||||
../data/mainwindow.css
|
||||
|
|
Loading…
Reference in New Issue