diff --git a/src/models/trackmetadatamodel.cpp b/src/models/trackmetadatamodel.cpp index 6e48ef7d..dc981a69 100644 --- a/src/models/trackmetadatamodel.cpp +++ b/src/models/trackmetadatamodel.cpp @@ -1,355 +1,398 @@ /* * Copyright 2018 Matthieu Gallien * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include "trackmetadatamodel.h" #include "musiclistenersmanager.h" #include +#include + TrackMetadataModel::TrackMetadataModel(QObject *parent) : QAbstractListModel(parent) { + connect(&mLyricsValueWatcher, &QFutureWatcher::finished, + this, &TrackMetadataModel::lyricsValueIsReady); +} + +TrackMetadataModel::~TrackMetadataModel() +{ + if (mLyricsValueWatcher.isRunning() && !mLyricsValueWatcher.isFinished()) { + mLyricsValueWatcher.waitForFinished(); + } } int TrackMetadataModel::rowCount(const QModelIndex &parent) const { if (parent.isValid()) { return 0; } return mTrackData.count(); } QVariant TrackMetadataModel::data(const QModelIndex &index, int role) const { auto result = QVariant{}; const auto currentKey = mTrackKeys[index.row()]; switch (role) { case Qt::DisplayRole: result = mTrackData[currentKey]; break; case ItemNameRole: switch (currentKey) { case DatabaseInterface::TitleRole: result = i18nc("Track title for track metadata view", "Title"); break; case DatabaseInterface::DurationRole: result = i18nc("Duration label for track metadata view", "Duration"); break; case DatabaseInterface::ArtistRole: result = i18nc("Track artist for track metadata view", "Artist"); break; case DatabaseInterface::AlbumRole: result = i18nc("Album name for track metadata view", "Album"); break; case DatabaseInterface::AlbumArtistRole: result = i18nc("Album artist for track metadata view", "Album Artist"); break; case DatabaseInterface::TrackNumberRole: result = i18nc("Track number for track metadata view", "Track Number"); break; case DatabaseInterface::DiscNumberRole: result = i18nc("Disc number for track metadata view", "Disc Number"); break; case DatabaseInterface::RatingRole: result = i18nc("Rating label for information panel", "Rating"); break; case DatabaseInterface::GenreRole: result = i18nc("Genre label for track metadata view", "Genre"); break; case DatabaseInterface::LyricistRole: result = i18nc("Lyricist label for track metadata view", "Lyricist"); break; case DatabaseInterface::ComposerRole: result = i18nc("Composer name for track metadata view", "Composer"); break; case DatabaseInterface::CommentRole: result = i18nc("Comment label for track metadata view", "Comment"); break; case DatabaseInterface::YearRole: result = i18nc("Year label for track metadata view", "Year"); break; case DatabaseInterface::ChannelsRole: result = i18nc("Channels label for track metadata view", "Channels"); break; case DatabaseInterface::BitRateRole: result = i18nc("Bit rate label for track metadata view", "Bit Rate"); break; case DatabaseInterface::SampleRateRole: result = i18nc("Sample Rate label for track metadata view", "Sample Rate"); break; case DatabaseInterface::LastPlayDate: result = i18nc("Last play date label for track metadata view", "Last played"); break; case DatabaseInterface::PlayCounter: result = i18nc("Play counter label for track metadata view", "Play count"); break; + case DatabaseInterface::LyricsRole: + result = i18nc("Lyrics label for track metadata view", "Lyrics"); + break; case DatabaseInterface::SecondaryTextRole: case DatabaseInterface::ImageUrlRole: case DatabaseInterface::ShadowForImageRole: case DatabaseInterface::ChildModelRole: case DatabaseInterface::StringDurationRole: case DatabaseInterface::MilliSecondsDurationRole: case DatabaseInterface::AllArtistsRole: case DatabaseInterface::HighestTrackRating: case DatabaseInterface::ResourceRole: case DatabaseInterface::IdRole: case DatabaseInterface::DatabaseIdRole: case DatabaseInterface::IsSingleDiscAlbumRole: case DatabaseInterface::ContainerDataRole: case DatabaseInterface::IsPartialDataRole: case DatabaseInterface::AlbumIdRole: case DatabaseInterface::HasEmbeddedCover: case DatabaseInterface::FileModificationTime: case DatabaseInterface::FirstPlayDate: case DatabaseInterface::PlayFrequency: case DatabaseInterface::ElementTypeRole: break; } break; case ItemTypeRole: switch (currentKey) { case DatabaseInterface::TitleRole: result = TextEntry; break; case DatabaseInterface::ArtistRole: result = TextEntry; break; case DatabaseInterface::AlbumRole: result = TextEntry; break; case DatabaseInterface::AlbumArtistRole: result = TextEntry; break; case DatabaseInterface::TrackNumberRole: result = IntegerEntry; break; case DatabaseInterface::DiscNumberRole: result = IntegerEntry; break; case DatabaseInterface::RatingRole: result = RatingEntry; break; case DatabaseInterface::GenreRole: result = TextEntry; break; case DatabaseInterface::LyricistRole: result = TextEntry; break; case DatabaseInterface::ComposerRole: result = TextEntry; break; case DatabaseInterface::CommentRole: result = TextEntry; break; case DatabaseInterface::YearRole: result = IntegerEntry; break; case DatabaseInterface::LastPlayDate: result = DateEntry; break; case DatabaseInterface::PlayCounter: result = IntegerEntry; break; + case DatabaseInterface::LyricsRole: + result = LongTextEntry; + break; case DatabaseInterface::DurationRole: case DatabaseInterface::SampleRateRole: case DatabaseInterface::BitRateRole: case DatabaseInterface::ChannelsRole: case DatabaseInterface::SecondaryTextRole: case DatabaseInterface::ImageUrlRole: case DatabaseInterface::ShadowForImageRole: case DatabaseInterface::ChildModelRole: case DatabaseInterface::StringDurationRole: case DatabaseInterface::MilliSecondsDurationRole: case DatabaseInterface::AllArtistsRole: case DatabaseInterface::HighestTrackRating: case DatabaseInterface::ResourceRole: case DatabaseInterface::IdRole: case DatabaseInterface::DatabaseIdRole: case DatabaseInterface::IsSingleDiscAlbumRole: case DatabaseInterface::ContainerDataRole: case DatabaseInterface::IsPartialDataRole: case DatabaseInterface::AlbumIdRole: case DatabaseInterface::HasEmbeddedCover: case DatabaseInterface::FileModificationTime: case DatabaseInterface::FirstPlayDate: case DatabaseInterface::PlayFrequency: case DatabaseInterface::ElementTypeRole: break; } break; } return result; } bool TrackMetadataModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (data(index, role) != value) { // FIXME: Implement me! emit dataChanged(index, index, QVector() << role); return true; } return false; } QHash TrackMetadataModel::roleNames() const { auto names = QAbstractListModel::roleNames(); names[ItemNameRole] = "name"; names[ItemTypeRole] = "type"; return names; } QString TrackMetadataModel::fileUrl() const { return mFileUrl; } const QUrl &TrackMetadataModel::coverUrl() const { return mCoverImage; } MusicListenersManager *TrackMetadataModel::manager() const { return mManager; } void TrackMetadataModel::trackData(const TrackMetadataModel::TrackDataType &trackData) { if (!mFullData.isEmpty() && trackData.databaseId() != mFullData.databaseId()) { return; } fillDataFromTrackData(trackData); } void TrackMetadataModel::fillDataFromTrackData(const TrackMetadataModel::TrackDataType &trackData) { beginResetModel(); mFullData = trackData; mTrackData.clear(); mTrackKeys.clear(); for (auto role : {DatabaseInterface::TitleRole, DatabaseInterface::ArtistRole, DatabaseInterface::AlbumRole, DatabaseInterface::AlbumArtistRole, DatabaseInterface::TrackNumberRole, DatabaseInterface::DiscNumberRole, DatabaseInterface::RatingRole, DatabaseInterface::GenreRole, DatabaseInterface::LyricistRole, DatabaseInterface::ComposerRole, DatabaseInterface::CommentRole, DatabaseInterface::YearRole, DatabaseInterface::LastPlayDate, DatabaseInterface::PlayCounter}) { if (trackData.constFind(role) != trackData.constEnd()) { if (role == DatabaseInterface::RatingRole) { if (trackData[role].toInt() == 0) { continue; } } mTrackKeys.push_back(role); mTrackData[role] = trackData[role]; } } filterDataFromTrackData(); endResetModel(); + fetchLyrics(); + mCoverImage = trackData[DatabaseInterface::ImageUrlRole].toUrl(); Q_EMIT coverUrlChanged(); auto rawFileUrl = trackData[DatabaseInterface::ResourceRole].toUrl(); if (rawFileUrl.isLocalFile()) { mFileUrl = rawFileUrl.toLocalFile(); } else { mFileUrl = rawFileUrl.toString(); } Q_EMIT fileUrlChanged(); } void TrackMetadataModel::filterDataFromTrackData() { } void TrackMetadataModel::removeMetaData(DatabaseInterface::ColumnsRoles metaData) { auto itMetaData = std::find(mTrackKeys.begin(), mTrackKeys.end(), metaData); if (itMetaData == mTrackKeys.end()) { return; } mTrackKeys.erase(itMetaData); mTrackData.remove(metaData); } TrackMetadataModel::TrackDataType::mapped_type TrackMetadataModel::dataFromType(TrackDataType::key_type metaData) const { return mFullData[metaData]; } +void TrackMetadataModel::lyricsValueIsReady() +{ + if (!mLyricsValueWatcher.result().isEmpty()) { + beginInsertRows({}, mTrackData.size(), mTrackData.size()); + mTrackKeys.push_back(DatabaseInterface::LyricsRole); + mTrackData[DatabaseInterface::LyricsRole] = mLyricsValueWatcher.result(); + mFullData[DatabaseInterface::LyricsRole] = mLyricsValueWatcher.result(); + endInsertRows(); + } +} + void TrackMetadataModel::initialize(MusicListenersManager *newManager, DatabaseInterface *trackDatabase) { mManager = newManager; Q_EMIT managerChanged(); if (mManager) { mDataLoader.setDatabase(mManager->viewDatabase()); } else if (trackDatabase) { mDataLoader.setDatabase(trackDatabase); } if (mManager) { mManager->connectModel(&mDataLoader); } connect(this, &TrackMetadataModel::needDataByDatabaseId, &mDataLoader, &ModelDataLoader::loadDataByDatabaseId); connect(this, &TrackMetadataModel::needDataByFileName, &mDataLoader, &ModelDataLoader::loadDataByFileName); connect(&mDataLoader, &ModelDataLoader::allTrackData, this, &TrackMetadataModel::trackData); connect(&mDataLoader, &ModelDataLoader::trackModified, this, &TrackMetadataModel::trackData); } +void TrackMetadataModel::fetchLyrics() +{ + auto lyricicsValue = QtConcurrent::run(QThreadPool::globalInstance(), [=]() { + auto trackData = mFileScanner.scanOneFile(mFullData[DatabaseInterface::ResourceRole].toUrl(), mMimeDatabase); + if (!trackData.lyrics().isEmpty()) { + return trackData.lyrics(); + } + return QString{}; + }); + + mLyricsValueWatcher.setFuture(lyricicsValue); +} + void TrackMetadataModel::initializeByTrackId(qulonglong databaseId) { Q_EMIT needDataByDatabaseId(ElisaUtils::Track, databaseId); } void TrackMetadataModel::initializeByTrackFileName(const QUrl &fileName) { Q_EMIT needDataByFileName(ElisaUtils::FileName, fileName); } void TrackMetadataModel::setManager(MusicListenersManager *newManager) { initialize(newManager, nullptr); } void TrackMetadataModel::setDatabase(DatabaseInterface *trackDatabase) { initialize(nullptr, trackDatabase); } #include "moc_trackmetadatamodel.cpp" diff --git a/src/models/trackmetadatamodel.h b/src/models/trackmetadatamodel.h index f17262f2..406e7df1 100644 --- a/src/models/trackmetadatamodel.h +++ b/src/models/trackmetadatamodel.h @@ -1,141 +1,159 @@ /* * Copyright 2018 Matthieu Gallien * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #ifndef TRACKMETADATAMODEL_H #define TRACKMETADATAMODEL_H #include "elisaLib_export.h" #include "elisautils.h" #include "databaseinterface.h" #include "modeldataloader.h" +#include "filescanner.h" #include #include +#include +#include class MusicListenersManager; class ELISALIB_EXPORT TrackMetadataModel : public QAbstractListModel { Q_OBJECT Q_PROPERTY(QUrl coverUrl READ coverUrl NOTIFY coverUrlChanged) Q_PROPERTY(QString fileUrl READ fileUrl NOTIFY fileUrlChanged) Q_PROPERTY(MusicListenersManager* manager READ manager WRITE setManager NOTIFY managerChanged) public: enum ColumnRoles { ItemNameRole = Qt::UserRole + 1, ItemTypeRole, }; enum ItemType { TextEntry, IntegerEntry, RatingEntry, DateEntry, + LongTextEntry, }; Q_ENUM(ItemType) using TrackDataType = DatabaseInterface::TrackDataType; explicit TrackMetadataModel(QObject *parent = nullptr); + ~TrackMetadataModel() override; + int rowCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; QHash roleNames() const override; const QUrl& coverUrl() const; QString fileUrl() const; MusicListenersManager* manager() const; Q_SIGNALS: void needDataByDatabaseId(ElisaUtils::PlayListEntryType dataType, qulonglong databaseId); void needDataByFileName(ElisaUtils::PlayListEntryType dataType, const QUrl &fileName); void coverUrlChanged(); void fileUrlChanged(); void managerChanged(); public Q_SLOTS: void trackData(const TrackMetadataModel::TrackDataType &trackData); void initializeByTrackId(qulonglong databaseId); void initializeByTrackFileName(const QUrl &fileName); void setManager(MusicListenersManager *newManager); void setDatabase(DatabaseInterface *trackDatabase); protected: void fillDataFromTrackData(const TrackMetadataModel::TrackDataType &trackData); virtual void filterDataFromTrackData(); void removeMetaData(DatabaseInterface::ColumnsRoles metaData); TrackDataType::mapped_type dataFromType(TrackDataType::key_type metaData) const; +private Q_SLOTS: + + void lyricsValueIsReady(); + private: void initialize(MusicListenersManager *newManager, DatabaseInterface *trackDatabase); + void fetchLyrics(); + TrackDataType mFullData; TrackDataType mTrackData; QUrl mCoverImage; QString mFileUrl; QList mTrackKeys; ModelDataLoader mDataLoader; MusicListenersManager *mManager = nullptr; + FileScanner mFileScanner; + + QMimeDatabase mMimeDatabase; + + QFutureWatcher mLyricsValueWatcher; + }; #endif // TRACKMETADATAMODEL_H diff --git a/src/qml/ContextView.qml b/src/qml/ContextView.qml index 9a2f7ca4..6156c638 100644 --- a/src/qml/ContextView.qml +++ b/src/qml/ContextView.qml @@ -1,199 +1,209 @@ /* * Copyright 2016 Matthieu Gallien * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ import QtQuick 2.10 import QtQuick.Window 2.2 import QtQuick.Controls 2.2 import QtQml.Models 2.2 import QtQuick.Layouts 1.2 import org.kde.elisa 1.0 FocusScope { id: topItem property int databaseId: 0 property alias title: titleLabel.text property string albumName: '' property string artistName: '' property url albumArtUrl: '' property string fileUrl: '' TrackContextMetaDataModel { id: metaDataModel manager: elisa.musicManager } ColumnLayout { anchors.fill: parent spacing: 0 TextMetrics { id: titleHeight text: viewTitleHeight.text font { pointSize: viewTitleHeight.font.pointSize bold: viewTitleHeight.font.bold } } LabelWithToolTip { id: viewTitleHeight text: i18nc("Title of the context view related to the currently playing track", "Now Playing") font.pointSize: elisaTheme.defaultFontPointSize * 2 Layout.alignment: Qt.AlignLeft | Qt.AlignTop Layout.topMargin: elisaTheme.layoutVerticalMargin * 3 Layout.bottomMargin: titleHeight.height } Image { id: albumIcon source: albumArtUrl.toString() === '' ? Qt.resolvedUrl(elisaTheme.defaultAlbumImage) : albumArtUrl Layout.fillWidth: true Layout.maximumHeight: elisaTheme.contextCoverImageSize Layout.preferredHeight: elisaTheme.contextCoverImageSize Layout.bottomMargin: elisaTheme.layoutVerticalMargin width: elisaTheme.contextCoverImageSize height: elisaTheme.contextCoverImageSize sourceSize.width: parent.width sourceSize.height: elisaTheme.contextCoverImageSize asynchronous: true fillMode: Image.PreserveAspectCrop } LabelWithToolTip { id: titleLabel font.pointSize: elisaTheme.defaultFontPointSize * 2 font.weight: Font.Bold Layout.alignment: Qt.AlignLeft | Qt.AlignTop Layout.topMargin: elisaTheme.layoutVerticalMargin elide: Text.ElideRight } LabelWithToolTip { id: albumArtistLabel text: (artistName && albumName ? i18nc('display of artist and album in context view', 'by %1 from %2', artistName, albumName) : '') font.pointSize: elisaTheme.defaultFontPointSize * 1.4 visible: artistName !== '' && albumName !== '' Layout.alignment: Qt.AlignLeft | Qt.AlignTop Layout.bottomMargin: elisaTheme.layoutVerticalMargin elide: Text.ElideRight } LabelWithToolTip { id: albumLabel text: (albumName ? i18nc('display of album in context view', 'from %1', albumName) : '') font.pointSize: elisaTheme.defaultFontPointSize * 1.4 visible: artistName === '' && albumName !== '' Layout.alignment: Qt.AlignLeft | Qt.AlignTop Layout.bottomMargin: elisaTheme.layoutVerticalMargin elide: Text.ElideRight } LabelWithToolTip { id: artistLabel text: (artistName ? i18nc('display of artist in context view', 'by %1', artistName) : '') font.pointSize: elisaTheme.defaultFontPointSize * 1.4 visible: artistName !== '' && albumName === '' Layout.alignment: Qt.AlignLeft | Qt.AlignTop Layout.bottomMargin: elisaTheme.layoutVerticalMargin elide: Text.ElideRight } - Repeater { + ListView { + id: trackData + + Layout.fillWidth: true + Layout.fillHeight: true + + ScrollBar.vertical: ScrollBar { + id: scrollBar + } + boundsBehavior: Flickable.StopAtBounds + clip: true + + spacing: 0 + model: metaDataModel delegate: MetaDataDelegate { + width: scrollBar.visible ? (!LayoutMirroring.enabled ? trackData.width - scrollBar.width : trackData.width) : trackData.width } } - Item { - Layout.fillHeight: true - } - Row { Layout.alignment: Qt.AlignLeft | Qt.AlignBottom Layout.topMargin: elisaTheme.layoutVerticalMargin Layout.bottomMargin: elisaTheme.layoutVerticalMargin spacing: elisaTheme.layoutHorizontalMargin Image { sourceSize.width: fileNameLabel.height sourceSize.height: fileNameLabel.height source: elisaTheme.folderIcon } LabelWithToolTip { id: fileNameLabel text: fileUrl elide: Text.ElideRight } } } onDatabaseIdChanged: { metaDataModel.initializeByTrackId(databaseId) } Connections { target: elisa onMusicManagerChanged: { metaDataModel.initializeByTrackId(databaseId) } } Component.onCompleted: { if (elisa.musicManager) { metaDataModel.initializeByTrackId(databaseId) } } } diff --git a/src/qml/MediaTrackMetadataView.qml b/src/qml/MediaTrackMetadataView.qml index c724e85e..5db25d56 100644 --- a/src/qml/MediaTrackMetadataView.qml +++ b/src/qml/MediaTrackMetadataView.qml @@ -1,245 +1,174 @@ /* * Copyright 2017 Alexander Stippich * Copyright 2018 Matthieu Gallien * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ import QtQuick 2.7 import QtQuick.Controls 2.2 import QtQuick.Window 2.2 import QtQml.Models 2.2 import QtQuick.Layouts 1.2 import QtGraphicalEffects 1.0 import org.kde.elisa 1.0 Window { id: trackMetadata property int databaseId: 0 property url fileName signal rejected() LayoutMirroring.enabled: Qt.application.layoutDirection == Qt.RightToLeft LayoutMirroring.childrenInherit: true title: i18nc("Window title for track metadata", "View Details") TrackMetadataModel { id: realModel manager: elisa.musicManager } modality: Qt.NonModal flags: Qt.Dialog | Qt.WindowCloseButtonHint color: myPalette.window minimumHeight: elisaTheme.coverImageSize * 1.8 minimumWidth: elisaTheme.coverImageSize * 2.8 ColumnLayout { anchors.fill: parent anchors.margins: elisaTheme.layoutVerticalMargin spacing: elisaTheme.layoutVerticalMargin RowLayout { id: metadataView Layout.fillHeight: true Layout.fillWidth: true spacing: 0 Image { source: (realModel.coverUrl !== "" ? realModel.coverUrl : elisaTheme.tracksIcon) sourceSize.width: elisaTheme.coverImageSize sourceSize.height: elisaTheme.coverImageSize fillMode: Image.PreserveAspectFit Layout.alignment: Qt.AlignTop | Qt.AlignHCenter Layout.preferredHeight: elisaTheme.coverImageSize Layout.preferredWidth: elisaTheme.coverImageSize Layout.minimumHeight: elisaTheme.coverImageSize Layout.minimumWidth: elisaTheme.coverImageSize Layout.maximumHeight: elisaTheme.coverImageSize Layout.maximumWidth: elisaTheme.coverImageSize } ListView { id: trackData Layout.fillWidth: true Layout.fillHeight: true + Layout.leftMargin: 2 * elisaTheme.layoutHorizontalMargin focus: true ScrollBar.vertical: ScrollBar { id: scrollBar } boundsBehavior: Flickable.StopAtBounds clip: true - ScrollHelper { id: scrollHelper flickable: trackData anchors.fill: trackData } model: realModel - delegate: metadataDelegate + delegate: MetaDataDelegate { + width: scrollBar.visible ? (!LayoutMirroring.enabled ? trackData.width - scrollBar.width : trackData.width) : trackData.width + } } } RowLayout { Layout.alignment: Qt.AlignLeft | Qt.AlignBottom Layout.topMargin: elisaTheme.layoutVerticalMargin Layout.bottomMargin: elisaTheme.layoutVerticalMargin spacing: elisaTheme.layoutHorizontalMargin Image { Layout.preferredWidth: fileNameLabel.height Layout.preferredHeight: fileNameLabel.height sourceSize.width: fileNameLabel.height sourceSize.height: fileNameLabel.height source: elisaTheme.folderIcon } LabelWithToolTip { id: fileNameLabel Layout.fillWidth: true text: realModel.fileUrl elide: Text.ElideRight } } DialogButtonBox { id: buttons Layout.fillWidth: true Layout.minimumHeight: implicitHeight standardButtons: DialogButtonBox.Close alignment: Qt.AlignRight onRejected: trackMetadata.rejected() } } - Component { - id: metadataDelegate - - RowLayout { - id: delegateRow - spacing: 0 - - width: scrollBar.visible ? trackData.width - scrollBar.width : trackData.width - - Label { - id: metaDataLabels - text: i18nc('name of a property for the track metadata detailled view', '%1:', model.name) - color: myPalette.text - horizontalAlignment: Text.AlignRight - - Layout.preferredWidth: 0.8 * elisaTheme.coverImageSize - Layout.rightMargin: !LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 - Layout.leftMargin: LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin : 0 - } - - Loader { - active: model.type === TrackMetadataModel.TextEntry || model.type === TrackMetadataModel.IntegerEntry - - Layout.fillWidth: true - - sourceComponent: LabelWithToolTip { - text: model.display - - horizontalAlignment: Text.AlignLeft - elide: Text.ElideRight - - anchors.fill: parent - } - } - - Loader { - active: model.type === TrackMetadataModel.DateEntry - - Layout.fillWidth: true - - sourceComponent: LabelWithToolTip { - text: rawDate.toLocaleDateString() - - horizontalAlignment: Text.AlignLeft - elide: Text.ElideRight - - anchors.fill: parent - - property date rawDate: new Date(model.display) - } - } - - Loader { - active: model.type === TrackMetadataModel.RatingEntry - - Layout.fillWidth: true - - sourceComponent: RatingStar { - starRating: model.display - starSize: elisaTheme.ratingStarSize - - readOnly: true - - anchors { - left: parent.left - top: parent.top - bottom: parent.bottom - } - } - } - } - } - Connections { target: elisa onMusicManagerChanged: { if (databaseId !== 0) { realModel.initializeByTrackId(databaseId) } else { realModel.initializeByTrackFileName(fileName) } } } Component.onCompleted: { if (elisa.musicManager) { if (databaseId !== 0) { realModel.initializeByTrackId(databaseId) } else { realModel.initializeByTrackFileName(fileName) } } } } diff --git a/src/qml/MetaDataDelegate.qml b/src/qml/MetaDataDelegate.qml index 5d9c90a1..f68e70c3 100644 --- a/src/qml/MetaDataDelegate.qml +++ b/src/qml/MetaDataDelegate.qml @@ -1,106 +1,133 @@ /* * Copyright 2016 Matthieu Gallien * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This program 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ import QtQuick 2.10 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.2 import org.kde.elisa 1.0 RowLayout { id: delegateRow spacing: 0 - width: topItem.width - height: metaDataLabelMetric.height * 1.5 + height: (model.type === TrackMetadataModel.LongTextEntry ? longTextDisplayLoader.height : metaDataLabelMetric.height) + (elisaTheme.layoutVerticalMargin / 2) TextMetrics { id: metaDataLabelMetric - text: model.name + text: 'Metadata Name' font.weight: Font.Bold } Label { id: metaDataLabels text: model.name font.weight: Font.Bold horizontalAlignment: Text.AlignLeft + Layout.alignment: Qt.AlignTop Layout.preferredWidth: 0.8 * elisaTheme.coverImageSize Layout.rightMargin: !LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin * 2 : 0 Layout.leftMargin: LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin * 2 : 0 } Loader { + id: textDisplayLoader + active: model.type === TrackMetadataModel.TextEntry || model.type === TrackMetadataModel.IntegerEntry visible: model.type === TrackMetadataModel.TextEntry || model.type === TrackMetadataModel.IntegerEntry Layout.fillWidth: true + Layout.alignment: Qt.AlignTop sourceComponent: LabelWithToolTip { text: model.display horizontalAlignment: Text.AlignLeft elide: Text.ElideRight anchors.fill: parent } } + Loader { + id: longTextDisplayLoader + + active: model.type === TrackMetadataModel.LongTextEntry + visible: model.type === TrackMetadataModel.LongTextEntry + + Layout.fillWidth: true + Layout.maximumWidth: delegateRow.width - (0.8 * elisaTheme.coverImageSize + elisaTheme.layoutHorizontalMargin * 2) + Layout.alignment: Qt.AlignTop + + sourceComponent: Label { + text: model.display + + horizontalAlignment: Text.AlignLeft + elide: Text.ElideRight + + anchors.fill: parent + + wrapMode: Text.WordWrap + } + } + Loader { active: model.type === TrackMetadataModel.DateEntry visible: model.type === TrackMetadataModel.DateEntry Layout.fillWidth: true + Layout.alignment: Qt.AlignTop sourceComponent: LabelWithToolTip { text: rawDate.toLocaleDateString() horizontalAlignment: Text.AlignLeft elide: Text.ElideRight anchors.fill: parent property date rawDate: new Date(model.display) } } Loader { active: model.type === TrackMetadataModel.RatingEntry visible: model.type === TrackMetadataModel.RatingEntry Layout.fillWidth: true + Layout.alignment: Qt.AlignTop sourceComponent: RatingStar { starRating: model.display starSize: elisaTheme.ratingStarSize readOnly: true anchors { left: parent.left top: parent.top bottom: parent.bottom } } } }