1
0
mirror of https://github.com/clementine-player/Clementine synced 2024-12-15 10:48:33 +01:00

Allow inline editing of tags in the playlist. Thanks christoph.gysin

This commit is contained in:
David Sansome 2010-03-25 23:48:58 +00:00
parent 11bd9966d1
commit 766429c860
7 changed files with 186 additions and 42 deletions

View File

@ -133,6 +133,7 @@ MainWindow::MainWindow(QNetworkAccessManager* network, QWidget *parent)
connect(ui_.action_edit_track, SIGNAL(triggered()), SLOT(EditTracks()));
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_configure, SIGNAL(triggered()), settings_dialog_, SLOT(show()));
connect(ui_.action_about, SIGNAL(triggered()), about_dialog_, SLOT(show()));
connect(ui_.action_shuffle, SIGNAL(triggered()), playlist_, SLOT(Shuffle()));
@ -244,6 +245,7 @@ MainWindow::MainWindow(QNetworkAccessManager* network, QWidget *parent)
playlist_menu_->addAction(ui_.action_remove_from_playlist);
playlist_menu_->addSeparator();
playlist_menu_->addAction(ui_.action_edit_track);
playlist_menu_->addAction(ui_.action_edit_value);
playlist_menu_->addAction(ui_.action_renumber_tracks);
playlist_menu_->addAction(ui_.action_selection_set_value);
playlist_menu_->addSeparator();
@ -587,17 +589,22 @@ void MainWindow::PlaylistRightClick(const QPoint& global_pos, const QModelIndex&
}
}
ui_.action_edit_track->setEnabled(editable);
ui_.action_renumber_tracks->setEnabled(editable);
ui_.action_selection_set_value->setEnabled(editable >= 2);
ui_.action_renumber_tracks->setVisible(editable);
ui_.action_selection_set_value->setVisible(editable >= 2);
ui_.action_edit_value->setVisible(editable);
ui_.action_remove_from_playlist->setEnabled(!selection.isEmpty());
if (!index.isValid()) {
ui_.action_selection_set_value->setVisible(false);
ui_.action_edit_value->setVisible(false);
} else {
Playlist::Column column = (Playlist::Column)index.column();
bool editable = Playlist::column_is_editable(column);
ui_.action_selection_set_value->setVisible(
column <= Playlist::Column_Genre &&
column != Playlist::Column_Length);
ui_.action_selection_set_value->isVisible() && editable);
ui_.action_edit_value->setVisible(
ui_.action_edit_value->isVisible() && editable);
QString column_name = Playlist::column_name(column);
QString column_value = playlist_->data(index).toString();
@ -606,6 +613,7 @@ void MainWindow::PlaylistRightClick(const QPoint& global_pos, const QModelIndex&
ui_.action_selection_set_value->setText(tr("Set %1 to \"%2\"...")
.arg(column_name.toLower()).arg(column_value));
ui_.action_edit_value->setText(tr("Edit tag \"%1\"...").arg(column_name));
}
playlist_menu_->popup(global_pos);
@ -685,44 +693,17 @@ void MainWindow::SelectionSetValue() {
int row = index.row();
Song song = playlist_->item_at(row)->Metadata();
if (song.IsEditable()) {
switch(column) {
case Playlist::Column_Title:
song.set_title(column_value.toString());
break;
case Playlist::Column_Artist:
song.set_artist(column_value.toString());
break;
case Playlist::Column_Album:
song.set_album(column_value.toString());
break;
case Playlist::Column_AlbumArtist:
song.set_albumartist(column_value.toString());
break;
case Playlist::Column_Composer:
song.set_composer(column_value.toString());
break;
case Playlist::Column_Track:
song.set_track(column_value.toInt());
break;
case Playlist::Column_Disc:
song.set_disc(column_value.toInt());
break;
case Playlist::Column_Year:
song.set_year(column_value.toInt());
break;
case Playlist::Column_Genre:
song.set_genre(column_value.toString());
break;
default:
break;
}
if(Playlist::set_column_value(song, column, column_value)) {
song.Save();
playlist_->item_at(row)->Reload();
}
}
}
void MainWindow::EditValue() {
ui_.playlist->edit(playlist_menu_index_);
}
void MainWindow::LibraryScanStarted() {
multi_loading_indicator_->TaskStarted(MultiLoadingIndicator::UpdatingLibrary);
}

View File

@ -75,6 +75,7 @@ class MainWindow : public QMainWindow {
void EditTracks();
void RenumberTracks();
void SelectionSetValue();
void EditValue();
void PlayIndex(const QModelIndex& index);
void StopAfterCurrent();

View File

@ -40,6 +40,9 @@
<property name="acceptDrops">
<bool>true</bool>
</property>
<property name="editTriggers">
<set>QAbstractItemView::SelectedClicked|QAbstractItemView::EditKeyPressed</set>
</property>
<property name="dragEnabled">
<bool>true</bool>
</property>
@ -665,6 +668,11 @@
<string>Set value for all selected tracks...</string>
</property>
</action>
<action name="action_edit_value">
<property name="text">
<string>Edit tag...</string>
</property>
</action>
<action name="action_configure">
<property name="icon">
<iconset resource="../data/data.qrc">

View File

@ -66,6 +66,64 @@ QVariant Playlist::headerData(int section, Qt::Orientation, int role) const {
return QVariant();
}
bool Playlist::column_is_editable(Playlist::Column column) {
switch(column) {
case Column_Title:
case Column_Artist:
case Column_Album:
case Column_AlbumArtist:
case Column_Composer:
case Column_Track:
case Column_Disc:
case Column_Year:
case Column_Genre:
return true;
default:
break;
}
return false;
}
bool Playlist::set_column_value(Song& song, Playlist::Column column,
const QVariant& value) {
if (!song.IsEditable())
return false;
switch(column) {
case Playlist::Column_Title:
song.set_title(value.toString());
break;
case Playlist::Column_Artist:
song.set_artist(value.toString());
break;
case Playlist::Column_Album:
song.set_album(value.toString());
break;
case Playlist::Column_AlbumArtist:
song.set_albumartist(value.toString());
break;
case Playlist::Column_Composer:
song.set_composer(value.toString());
break;
case Playlist::Column_Track:
song.set_track(value.toInt());
break;
case Playlist::Column_Disc:
song.set_disc(value.toInt());
break;
case Playlist::Column_Year:
song.set_year(value.toInt());
break;
case Playlist::Column_Genre:
song.set_genre(value.toString());
break;
default:
break;
}
return true;
}
QVariant Playlist::data(const QModelIndex& index, int role) const {
switch (role) {
case Role_IsCurrent:
@ -77,6 +135,7 @@ QVariant Playlist::data(const QModelIndex& index, int role) const {
case Role_StopAfter:
return stop_after_.isValid() && stop_after_.row() == index.row();
case Qt::EditRole:
case Qt::DisplayRole: {
PlaylistItem* item = items_[index.row()];
Song song = item->Metadata();
@ -112,6 +171,18 @@ QVariant Playlist::data(const QModelIndex& index, int role) const {
}
}
bool Playlist::setData(const QModelIndex &index, const QVariant &value, int role) {
int row = index.row();
Song song = item_at(row)->Metadata();
if(!set_column_value(song, (Column)index.column(), value))
return false;
song.Save();
item_at(row)->Reload();
return true;
}
int Playlist::current_index() const {
return current_item_.isValid() ? current_item_.row() : -1;
}
@ -222,9 +293,16 @@ void Playlist::set_current_index(int i) {
}
Qt::ItemFlags Playlist::flags(const QModelIndex &index) const {
Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
if(column_is_editable((Column)index.column()))
flags |= Qt::ItemIsEditable;
if (index.isValid())
return Qt::ItemIsDragEnabled | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
return Qt::ItemIsDropEnabled | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
return flags | Qt::ItemIsDragEnabled;
return Qt::ItemIsDropEnabled;
}
QStringList Playlist::mimeTypes() const {

View File

@ -72,6 +72,8 @@ class Playlist : public QAbstractListModel {
const PlaylistItem* a, const PlaylistItem* b);
static QString column_name(Column column);
static bool column_is_editable(Playlist::Column column);
static bool set_column_value(Song& song, Column column, const QVariant& value);
// Persistence
void Save() const;
@ -110,6 +112,7 @@ class Playlist : public QAbstractListModel {
int rowCount(const QModelIndex& = QModelIndex()) const { return items_.count(); }
int columnCount(const QModelIndex& = QModelIndex()) const { return ColumnCount; }
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
bool setData(const QModelIndex &index, const QVariant &value, int role);
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
Qt::ItemFlags flags(const QModelIndex &index) const;
QStringList mimeTypes() const;

View File

@ -349,10 +349,9 @@ bool CompareSelectionRanges(const QItemSelectionRange& a, const QItemSelectionRa
void PlaylistView::keyPressEvent(QKeyEvent* event) {
if (!model()) {
QTreeView::keyPressEvent(event);
return;
}
if (event->matches(QKeySequence::Delete) ||
} else if (state() == QAbstractItemView::EditingState) {
QTreeView::keyPressEvent(event);
} else if (event->matches(QKeySequence::Delete) ||
event->key() == Qt::Key_Backspace) {
RemoveSelected();
event->accept();
@ -390,3 +389,71 @@ void PlaylistView::RemoveSelected() {
currentIndex().sibling(currentIndex().row(), model()->columnCount()-1)),
QItemSelectionModel::Select);
}
QList<int> PlaylistView::GetEditableColumns() {
QList<int> columns;
QHeaderView* h = header();
for (int col=0; col<h->count(); col++) {
if (h->isSectionHidden(col))
continue;
QModelIndex index = model()->index(0, col);
if (index.flags() & Qt::ItemIsEditable)
columns << h->visualIndex(col);
}
qSort(columns);
return columns;
}
QModelIndex PlaylistView::NextEditableIndex(const QModelIndex& current) {
QList<int> columns = GetEditableColumns();
QHeaderView* h = header();
int col = h->visualIndex(current.column());
QList<int> columns_left = columns.mid(columns.indexOf(col)+1);
QModelIndex index;
if(columns_left.empty())
index = model()->index(current.row()+1, h->logicalIndex(columns.first()));
else
index = model()->index(current.row(), h->logicalIndex(columns_left.first()));
return index;
}
QModelIndex PlaylistView::PrevEditableIndex(const QModelIndex& current) {
QList<int> columns = GetEditableColumns();
QHeaderView* h = header();
int col = h->visualIndex(current.column());
QList<int> columns_left = columns.mid(0, columns.indexOf(col));
QModelIndex index;
if(columns_left.empty())
index = model()->index(current.row()-1, h->logicalIndex(columns.last()));
else
index = model()->index(current.row(), h->logicalIndex(columns_left.last()));
return index;
}
void PlaylistView::closeEditor(QWidget* editor, QAbstractItemDelegate::EndEditHint hint) {
if (hint == QAbstractItemDelegate::NoHint) {
QTreeView::closeEditor(editor, QAbstractItemDelegate::SubmitModelCache);
} else if (hint == QAbstractItemDelegate::EditNextItem ||
hint == QAbstractItemDelegate::EditPreviousItem) {
QModelIndex index;
if (hint == QAbstractItemDelegate::EditNextItem)
index = NextEditableIndex(currentIndex());
else
index = PrevEditableIndex(currentIndex());
if (!index.isValid()) {
QTreeView::closeEditor(editor, QAbstractItemDelegate::SubmitModelCache);
} else {
QTreeView::closeEditor(editor, QAbstractItemDelegate::NoHint);
setCurrentIndex(index);
edit(index);
}
} else {
QTreeView::closeEditor(editor, hint);
}
}

View File

@ -23,6 +23,7 @@
class RadioLoadingIndicator;
class PlaylistDelegateBase : public QStyledItemDelegate {
Q_OBJECT
public:
PlaylistDelegateBase(QTreeView* view);
void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const;
@ -78,6 +79,7 @@ class PlaylistView : public QTreeView {
public slots:
void StopGlowing();
void StartGlowing();
void closeEditor(QWidget* editor, QAbstractItemDelegate::EndEditHint hint);
signals:
void PlayPauseItem(const QModelIndex& index);
@ -100,6 +102,10 @@ class PlaylistView : public QTreeView {
static const char* kSettingsGroup;
static const int kGlowIntensitySteps;
QList<int> GetEditableColumns();
QModelIndex NextEditableIndex(const QModelIndex& current);
QModelIndex PrevEditableIndex(const QModelIndex& current);
bool glow_enabled_;
QTimer* glow_timer_;
int glow_intensity_step_;