Use autocompletion in the edit tag dialog too. Thanks christoph.gysin. Fixes issue #130

This commit is contained in:
David Sansome 2010-03-29 16:59:01 +00:00
parent 227c64177c
commit afe2aadcf6
8 changed files with 318 additions and 244 deletions

View File

@ -65,6 +65,7 @@ set(CLEMENTINE-SOURCES
fixlastfm.cpp
backgroundthread.cpp
osdpretty.cpp
playlistdelegates.cpp
)
# Header files that have Q_OBJECT in
@ -122,6 +123,7 @@ set(CLEMENTINE-MOC-HEADERS
analyzers/turbine.h
globalshortcuts/globalshortcuts.h
osdpretty.h
playlistdelegates.h
)
# UI files

View File

@ -14,8 +14,9 @@
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "playlistdelegates.h"
#include "edittagdialog.h"
#include "ui_edittagdialog.h"
#include "library.h"
#include <QtDebug>
@ -92,6 +93,11 @@ bool EditTagDialog::SetSongs(const SongList &s) {
return true;
}
void EditTagDialog::SetTagCompleter(Library* library) {
new TagCompleter(library, Playlist::Column_Artist, ui_.artist);
new TagCompleter(library, Playlist::Column_Album, ui_.album);
}
void EditTagDialog::accept() {
foreach (const Song& old, songs_) {
Song song(old);

View File

@ -22,6 +22,8 @@
#include "ui_edittagdialog.h"
#include "song.h"
class Library;
class EditTagDialog : public QDialog {
Q_OBJECT
@ -29,6 +31,7 @@ class EditTagDialog : public QDialog {
EditTagDialog(QWidget* parent = 0);
bool SetSongs(const SongList& songs);
void SetTagCompleter(Library* library);
public slots:
void accept();

View File

@ -657,6 +657,8 @@ void MainWindow::EditTracks() {
}
edit_tag_dialog_->SetSongs(songs);
edit_tag_dialog_->SetTagCompleter(library_);
if (edit_tag_dialog_->exec() == QDialog::Rejected)
return;

207
src/playlistdelegates.cpp Normal file
View File

@ -0,0 +1,207 @@
/* This file is part of Clementine.
Clementine 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.
Clementine 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 Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "playlistdelegates.h"
#include "trackslider.h"
#include <QDateTime>
#include <QLineEdit>
#include <QPainter>
PlaylistDelegateBase::PlaylistDelegateBase(QTreeView* view)
: QStyledItemDelegate(view),
view_(view)
{
}
QString PlaylistDelegateBase::displayText(const QVariant& value, const QLocale&) const {
switch (value.type()) {
case QVariant::Int: {
int v = value.toInt();
if (v <= 0)
return QString::null;
return QString::number(v);
}
case QVariant::Double: {
double v = value.toDouble();
if (v <= 0)
return QString::null;
return QString::number(v);
}
default:
return value.toString();
}
}
void PlaylistDelegateBase::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const {
QStyledItemDelegate::paint(painter, Adjusted(option, index), index);
if (view_->header()->logicalIndexAt(QPoint(0,0)) == index.column()) {
if (index.data(Playlist::Role_StopAfter).toBool()) {
QColor color(Qt::white);
if (!index.data(Playlist::Role_IsCurrent).toBool() &&
!(option.state & QStyle::State_Selected)) {
color = option.palette.color(QPalette::Highlight);
}
const int kStopSize = 10;
const int kStopBorder = 2;
QRect stop_rect(option.rect);
stop_rect.setLeft(stop_rect.right() - kStopSize - kStopBorder);
stop_rect.setWidth(kStopSize);
stop_rect.moveTop(stop_rect.top() + (stop_rect.height() - kStopSize) / 2);
stop_rect.setHeight(kStopSize);
painter->setOpacity(0.65);
painter->fillRect(stop_rect, color);
painter->setOpacity(1.0);
}
}
}
QStyleOptionViewItemV4 PlaylistDelegateBase::Adjusted(const QStyleOptionViewItem& option, const QModelIndex& index) const {
if (view_->header()->logicalIndexAt(QPoint(0,0)) != index.column())
return option;
QStyleOptionViewItemV4 ret(option);
if (index.data(Playlist::Role_IsCurrent).toBool()) {
// Move the text in a bit on the first column for the song that's currently
// playing
ret.rect.setLeft(ret.rect.left() + 20);
}
return ret;
}
QString LengthItemDelegate::displayText(const QVariant& value, const QLocale&) const {
bool ok = false;
int seconds = value.toInt(&ok);
if (ok && seconds > 0)
return TrackSlider::PrettyTime(seconds);
return QString::null;
}
QString SizeItemDelegate::displayText(const QVariant& value, const QLocale&) const {
bool ok = false;
int bytes = value.toInt(&ok);
QString ret;
if (ok && bytes > 0) {
if (bytes <= 1024)
ret.sprintf("%d bytes", bytes);
else if (bytes <= 1024*1024)
ret.sprintf("%.1f KB", float(bytes) / 1024);
else if (bytes <= 1024*1024*1024)
ret.sprintf("%.1f MB", float(bytes) / (1024*1024));
else
ret.sprintf("%.1f GB", float(bytes) / (1024*1024*1024));
}
return ret;
}
QString DateItemDelegate::displayText(const QVariant &value, const QLocale &locale) const {
bool ok = false;
int time = value.toInt(&ok);
if (!ok || time == -1)
return QString::null;
return QDateTime::fromTime_t(time).toString(
QLocale::system().dateTimeFormat(QLocale::ShortFormat));
}
QString FileTypeItemDelegate::displayText(const QVariant &value, const QLocale &locale) const {
bool ok = false;
Song::FileType type = Song::FileType(value.toInt(&ok));
if (!ok)
return tr("Unknown");
switch (type) {
case Song::Type_Asf: return tr("ASF");
case Song::Type_Flac: return tr("FLAC");
case Song::Type_Mp4: return tr("MP4");
case Song::Type_Mpc: return tr("MPC");
case Song::Type_Mpeg: return tr("MP3"); // Not technically correct
case Song::Type_OggFlac: return tr("Ogg FLAC");
case Song::Type_OggSpeex: return tr("Ogg Speex");
case Song::Type_OggVorbis: return tr("Ogg Vorbis");
case Song::Type_Aiff: return tr("AIFF");
case Song::Type_Wav: return tr("WAV");
case Song::Type_TrueAudio: return tr("TrueAudio");
case Song::Type_Stream: return tr("Stream");
case Song::Type_Unknown:
default:
return tr("Unknown");
}
}
QWidget* TextItemDelegate::createEditor(
QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const {
return new QLineEdit(parent);
}
TagCompletionModel::TagCompletionModel(Library* library, Playlist::Column column) :
QStringListModel() {
switch(column) {
case Playlist::Column_Artist: {
setStringList(library->GetBackend()->GetAllArtists());
break;
}
case Playlist::Column_Album: {
QStringList album_names;
LibraryBackend::AlbumList albums = library->GetBackend()->GetAllAlbums();
foreach(const LibraryBackend::Album& album, albums)
album_names << album.album_name;
setStringList(album_names);
break;
}
case Playlist::Column_AlbumArtist: {
// TODO: get all albumartists?
break;
}
default:
break;
}
}
TagCompleter::TagCompleter(Library* library, Playlist::Column column, QLineEdit* editor) :
QCompleter(editor) {
setModel(new TagCompletionModel(library, column));
setCaseSensitivity(Qt::CaseInsensitive);
editor->setCompleter(this);
}
QWidget* TagCompletionItemDelegate::createEditor(
QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const {
QLineEdit* editor = new QLineEdit(parent);
new TagCompleter(library_, column_, editor);
return editor;
}

95
src/playlistdelegates.h Normal file
View File

@ -0,0 +1,95 @@
/* This file is part of Clementine.
Clementine 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.
Clementine 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 Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PLAYLISTDELEGATES_H
#define PLAYLISTDELEGATES_H
#include "playlist.h"
#include "library.h"
#include <QStyledItemDelegate>
#include <QTreeView>
#include <QStringListModel>
#include <QCompleter>
class PlaylistDelegateBase : public QStyledItemDelegate {
Q_OBJECT
public:
PlaylistDelegateBase(QTreeView* view);
void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const;
QString displayText(const QVariant& value, const QLocale& locale) const;
QStyleOptionViewItemV4 Adjusted(const QStyleOptionViewItem& option, const QModelIndex& index) const;
protected:
QTreeView* view_;
};
class LengthItemDelegate : public PlaylistDelegateBase {
public:
LengthItemDelegate(QTreeView* view) : PlaylistDelegateBase(view) {}
QString displayText(const QVariant& value, const QLocale& locale) const;
};
class SizeItemDelegate : public PlaylistDelegateBase {
public:
SizeItemDelegate(QTreeView* view) : PlaylistDelegateBase(view) {}
QString displayText(const QVariant& value, const QLocale& locale) const;
};
class DateItemDelegate : public PlaylistDelegateBase {
public:
DateItemDelegate(QTreeView* view) : PlaylistDelegateBase(view) {}
QString displayText(const QVariant& value, const QLocale& locale) const;
};
class FileTypeItemDelegate : public PlaylistDelegateBase {
public:
FileTypeItemDelegate(QTreeView* view) : PlaylistDelegateBase(view) {}
QString displayText(const QVariant& value, const QLocale& locale) const;
};
class TextItemDelegate : public PlaylistDelegateBase {
public:
TextItemDelegate(QTreeView* view) : PlaylistDelegateBase(view) {};
QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option,
const QModelIndex& index) const;
};
class TagCompletionModel : public QStringListModel {
public:
TagCompletionModel(Library* library, Playlist::Column column);
};
class TagCompleter : public QCompleter {
public:
TagCompleter(Library* library, Playlist::Column column, QLineEdit* editor);
};
class TagCompletionItemDelegate : public PlaylistDelegateBase {
public:
TagCompletionItemDelegate(QTreeView* view, Library* library, Playlist::Column column) :
PlaylistDelegateBase(view), library_(library), column_(column) {};
QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option,
const QModelIndex& index) const;
private:
Library* library_;
Playlist::Column column_;
};
#endif // PLAYLISTDELEGATES_H

View File

@ -17,7 +17,8 @@
#include "playlistview.h"
#include "playlist.h"
#include "playlistheader.h"
#include "trackslider.h"
#include "playlistdelegates.h"
#include "playlist.h"
#include <QPainter>
#include <QHeaderView>
@ -25,11 +26,6 @@
#include <QtDebug>
#include <QTimer>
#include <QKeyEvent>
#include <QMenu>
#include <QScrollBar>
#include <QDateTime>
#include <QLineEdit>
#include <QCompleter>
#include <math.h>
@ -37,184 +33,6 @@ const char* PlaylistView::kSettingsGroup = "Playlist";
const int PlaylistView::kGlowIntensitySteps = 32;
PlaylistDelegateBase::PlaylistDelegateBase(QTreeView* view)
: QStyledItemDelegate(view),
view_(view)
{
}
QString PlaylistDelegateBase::displayText(const QVariant& value, const QLocale&) const {
switch (value.type()) {
case QVariant::Int: {
int v = value.toInt();
if (v <= 0)
return QString::null;
return QString::number(v);
}
case QVariant::Double: {
double v = value.toDouble();
if (v <= 0)
return QString::null;
return QString::number(v);
}
default:
return value.toString();
}
}
void PlaylistDelegateBase::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const {
QStyledItemDelegate::paint(painter, Adjusted(option, index), index);
if (view_->header()->logicalIndexAt(QPoint(0,0)) == index.column()) {
if (index.data(Playlist::Role_StopAfter).toBool()) {
QColor color(Qt::white);
if (!index.data(Playlist::Role_IsCurrent).toBool() &&
!(option.state & QStyle::State_Selected)) {
color = option.palette.color(QPalette::Highlight);
}
const int kStopSize = 10;
const int kStopBorder = 2;
QRect stop_rect(option.rect);
stop_rect.setLeft(stop_rect.right() - kStopSize - kStopBorder);
stop_rect.setWidth(kStopSize);
stop_rect.moveTop(stop_rect.top() + (stop_rect.height() - kStopSize) / 2);
stop_rect.setHeight(kStopSize);
painter->setOpacity(0.65);
painter->fillRect(stop_rect, color);
painter->setOpacity(1.0);
}
}
}
QStyleOptionViewItemV4 PlaylistDelegateBase::Adjusted(const QStyleOptionViewItem& option, const QModelIndex& index) const {
if (view_->header()->logicalIndexAt(QPoint(0,0)) != index.column())
return option;
QStyleOptionViewItemV4 ret(option);
if (index.data(Playlist::Role_IsCurrent).toBool()) {
// Move the text in a bit on the first column for the song that's currently
// playing
ret.rect.setLeft(ret.rect.left() + 20);
}
return ret;
}
QString LengthItemDelegate::displayText(const QVariant& value, const QLocale&) const {
bool ok = false;
int seconds = value.toInt(&ok);
if (ok && seconds > 0)
return TrackSlider::PrettyTime(seconds);
return QString::null;
}
QString SizeItemDelegate::displayText(const QVariant& value, const QLocale&) const {
bool ok = false;
int bytes = value.toInt(&ok);
QString ret;
if (ok && bytes > 0) {
if (bytes <= 1024)
ret.sprintf("%d bytes", bytes);
else if (bytes <= 1024*1024)
ret.sprintf("%.1f KB", float(bytes) / 1024);
else if (bytes <= 1024*1024*1024)
ret.sprintf("%.1f MB", float(bytes) / (1024*1024));
else
ret.sprintf("%.1f GB", float(bytes) / (1024*1024*1024));
}
return ret;
}
QString DateItemDelegate::displayText(const QVariant &value, const QLocale &locale) const {
bool ok = false;
int time = value.toInt(&ok);
if (!ok || time == -1)
return QString::null;
return QDateTime::fromTime_t(time).toString(
QLocale::system().dateTimeFormat(QLocale::ShortFormat));
}
QString FileTypeItemDelegate::displayText(const QVariant &value, const QLocale &locale) const {
bool ok = false;
Song::FileType type = Song::FileType(value.toInt(&ok));
if (!ok)
return tr("Unknown");
switch (type) {
case Song::Type_Asf: return tr("ASF");
case Song::Type_Flac: return tr("FLAC");
case Song::Type_Mp4: return tr("MP4");
case Song::Type_Mpc: return tr("MPC");
case Song::Type_Mpeg: return tr("MP3"); // Not technically correct
case Song::Type_OggFlac: return tr("Ogg FLAC");
case Song::Type_OggSpeex: return tr("Ogg Speex");
case Song::Type_OggVorbis: return tr("Ogg Vorbis");
case Song::Type_Aiff: return tr("AIFF");
case Song::Type_Wav: return tr("WAV");
case Song::Type_TrueAudio: return tr("TrueAudio");
case Song::Type_Stream: return tr("Stream");
case Song::Type_Unknown:
default:
return tr("Unknown");
}
}
QWidget* TextItemDelegate::createEditor(
QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const {
return new QLineEdit(parent);
}
QWidget* TagCompletionItemDelegate::createEditor(
QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const {
QStringList choices;
switch(column_) {
case Playlist::Column_Artist: {
choices = library_->GetBackend()->GetAllArtists();
break;
}
case Playlist::Column_Album: {
// TODO: add optimised query to library backend?
LibraryBackend::AlbumList albums = library_->GetBackend()->GetAllAlbums();
foreach(const LibraryBackend::Album& album, albums)
choices << album.album_name;
break;
}
case Playlist::Column_AlbumArtist: {
// TODO: get all albumartists?
break;
}
default:
break;
}
QLineEdit* editor = new QLineEdit(parent);
if(!choices.isEmpty()) {
QCompleter* completer = new QCompleter(choices, editor);
completer->setCaseSensitivity(Qt::CaseInsensitive);
editor->setCompleter(completer);
}
return editor;
}
PlaylistView::PlaylistView(QWidget *parent)
: QTreeView(parent),
glow_enabled_(false),

View File

@ -20,69 +20,10 @@
#include "playlist.h"
#include "library.h"
#include <QStyledItemDelegate>
#include <QTreeView>
class RadioLoadingIndicator;
class PlaylistDelegateBase : public QStyledItemDelegate {
Q_OBJECT
public:
PlaylistDelegateBase(QTreeView* view);
void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const;
QString displayText(const QVariant& value, const QLocale& locale) const;
QStyleOptionViewItemV4 Adjusted(const QStyleOptionViewItem& option, const QModelIndex& index) const;
protected:
QTreeView* view_;
};
class LengthItemDelegate : public PlaylistDelegateBase {
public:
LengthItemDelegate(QTreeView* view) : PlaylistDelegateBase(view) {}
QString displayText(const QVariant& value, const QLocale& locale) const;
};
class SizeItemDelegate : public PlaylistDelegateBase {
public:
SizeItemDelegate(QTreeView* view) : PlaylistDelegateBase(view) {}
QString displayText(const QVariant& value, const QLocale& locale) const;
};
class DateItemDelegate : public PlaylistDelegateBase {
public:
DateItemDelegate(QTreeView* view) : PlaylistDelegateBase(view) {}
QString displayText(const QVariant& value, const QLocale& locale) const;
};
class FileTypeItemDelegate : public PlaylistDelegateBase {
public:
FileTypeItemDelegate(QTreeView* view) : PlaylistDelegateBase(view) {}
QString displayText(const QVariant& value, const QLocale& locale) const;
};
class TextItemDelegate : public PlaylistDelegateBase {
public:
TextItemDelegate(QTreeView* view) : PlaylistDelegateBase(view) {};
QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option,
const QModelIndex& index) const;
};
class TagCompletionItemDelegate : public PlaylistDelegateBase {
public:
TagCompletionItemDelegate(QTreeView* view, Library* library, Playlist::Column column) :
PlaylistDelegateBase(view), library_(library), column_(column) {};
QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option,
const QModelIndex& index) const;
private:
Library* library_;
Playlist::Column column_;
};
class PlaylistView : public QTreeView {
Q_OBJECT