diff --git a/src/elisaapplication.cpp b/src/elisaapplication.cpp index abf848e7..6f78f48d 100644 --- a/src/elisaapplication.cpp +++ b/src/elisaapplication.cpp @@ -1,484 +1,485 @@ /* * Copyright 2017 Matthieu Gallien * Copyright (C) 2012 Aleix Pol Gonzalez * * 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 "elisaapplication.h" #include "musiclistenersmanager.h" #include "mediaplaylist.h" #include "audiowrapper.h" #include "manageaudioplayer.h" #include "managemediaplayercontrol.h" #include "manageheaderbar.h" #include "elisa_settings.h" #include #if defined KF5ConfigWidgets_FOUND && KF5ConfigWidgets_FOUND #include #endif #if defined KF5XmlGui_FOUND && KF5XmlGui_FOUND #include #include #include #include #include #endif #if defined KF5KCMUtils_FOUND && KF5KCMUtils_FOUND #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include class ElisaApplicationPrivate { public: explicit ElisaApplicationPrivate(QObject *parent) #if defined KF5XmlGui_FOUND && KF5XmlGui_FOUND : mCollection(parent) #endif { Q_UNUSED(parent) auto configurationFileName = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation); configurationFileName += QStringLiteral("/elisarc"); Elisa::ElisaConfiguration::instance(configurationFileName); Elisa::ElisaConfiguration::self()->load(); Elisa::ElisaConfiguration::self()->save(); } #if defined KF5XmlGui_FOUND && KF5XmlGui_FOUND KActionCollection mCollection; #endif ElisaUtils::EntryDataList mArguments; std::unique_ptr mMusicManager; std::unique_ptr mMediaPlayList; std::unique_ptr mAudioWrapper; std::unique_ptr mAudioControl; std::unique_ptr mPlayerControl; std::unique_ptr mManageHeaderBar; }; ElisaApplication::ElisaApplication(QObject *parent) : QObject(parent), d(std::make_unique(this)) { } ElisaApplication::~ElisaApplication() = default; void ElisaApplication::setupActions(const QString &actionName) { #if defined KF5XmlGui_FOUND && KF5XmlGui_FOUND if (actionName == QStringLiteral("file_quit")) { auto quitAction = KStandardAction::quit(QCoreApplication::instance(), &QCoreApplication::quit, &d->mCollection); d->mCollection.addAction(actionName, quitAction); } if (actionName == QStringLiteral("help_contents") && KAuthorized::authorizeAction(actionName)) { auto handBookAction = KStandardAction::helpContents(this, &ElisaApplication::appHelpActivated, &d->mCollection); d->mCollection.addAction(handBookAction->objectName(), handBookAction); } if (actionName == QStringLiteral("help_report_bug") && KAuthorized::authorizeAction(actionName) && !KAboutData::applicationData().bugAddress().isEmpty()) { auto reportBugAction = KStandardAction::reportBug(this, &ElisaApplication::reportBug, &d->mCollection); d->mCollection.addAction(reportBugAction->objectName(), reportBugAction); } if (actionName == QStringLiteral("help_about_app") && KAuthorized::authorizeAction(actionName)) { auto aboutAppAction = KStandardAction::aboutApp(this, &ElisaApplication::aboutApplication, this); d->mCollection.addAction(aboutAppAction->objectName(), aboutAppAction); } if (actionName == QStringLiteral("options_configure") && KAuthorized::authorizeAction(actionName)) { auto preferencesAction = KStandardAction::preferences(this, &ElisaApplication::configureElisa, this); d->mCollection.addAction(preferencesAction->objectName(), preferencesAction); } if (actionName == QStringLiteral("options_configure_keybinding") && KAuthorized::authorizeAction(actionName)) { auto keyBindingsAction = KStandardAction::keyBindings(this, &ElisaApplication::configureShortcuts, this); d->mCollection.addAction(keyBindingsAction->objectName(), keyBindingsAction); } if (actionName == QStringLiteral("go_back") && KAuthorized::authorizeAction(actionName)) { auto goBackAction = KStandardAction::back(this, &ElisaApplication::goBack, this); d->mCollection.addAction(goBackAction->objectName(), goBackAction); } if (actionName == QStringLiteral("toggle_playlist") && KAuthorized::authorizeAction(actionName)) { auto togglePlaylistAction = d->mCollection.addAction(actionName, this, &ElisaApplication::togglePlaylist); togglePlaylistAction->setShortcut(QKeySequence(Qt::Key_F9)); togglePlaylistAction->setText(QStringLiteral("Toggle Playlist")); } if (actionName == QStringLiteral("Seek") && KAuthorized::authorizeAction(actionName)) { auto seekAction = d->mCollection.addAction(actionName, this, &ElisaApplication::seek); d->mCollection.setDefaultShortcut(seekAction, QKeySequence(tr("Shift+Right"))); } if (actionName == QStringLiteral("Scrub") && KAuthorized::authorizeAction(actionName)) { auto scrubAction = d->mCollection.addAction(actionName, this, &ElisaApplication::scrub); d->mCollection.setDefaultShortcut(scrubAction, QKeySequence(tr("Shift+Left"))); } if (actionName == QStringLiteral("Play-Pause") && KAuthorized::authorizeAction(actionName)) { auto playPauseAction = d->mCollection.addAction(actionName, this, &ElisaApplication::playPause); d->mCollection.setDefaultShortcut(playPauseAction, QKeySequence(tr("Space"))); } if (actionName == QStringLiteral("edit_find") && KAuthorized::authorizeAction(actionName)) { auto findAction = KStandardAction::find(this, &ElisaApplication::find, this); d->mCollection.addAction(findAction->objectName(), findAction); } d->mCollection.readSettings(); #endif } void ElisaApplication::setArguments(const ElisaUtils::EntryDataList &newArguments) { if (d->mArguments == newArguments) { return; } d->mArguments = checkFileListAndMakeAbsolute(newArguments, QDir::currentPath()); Q_EMIT argumentsChanged(); if (!d->mArguments.isEmpty()) { Q_EMIT enqueue(d->mArguments, ElisaUtils::FileName, ElisaUtils::PlayListEnqueueMode::AppendPlayList, ElisaUtils::PlayListEnqueueTriggerPlay::TriggerPlay); } } void ElisaApplication::activateActionRequested(const QString &actionName, const QVariant ¶meter) { Q_UNUSED(actionName) Q_UNUSED(parameter) } void ElisaApplication::activateRequested(const QStringList &arguments, const QString &workingDirectory) { if (arguments.size() > 1) { auto realArguments = ElisaUtils::EntryDataList{}; bool isFirst = true; for (const auto &oneArgument : arguments) { if (isFirst) { isFirst = false; continue; } realArguments.push_back(ElisaUtils::EntryData{0, oneArgument}); } Q_EMIT enqueue(checkFileListAndMakeAbsolute(realArguments, workingDirectory), ElisaUtils::FileName, ElisaUtils::PlayListEnqueueMode::AppendPlayList, ElisaUtils::PlayListEnqueueTriggerPlay::TriggerPlay); } } void ElisaApplication::openRequested(const QList &uris) { Q_UNUSED(uris) } void ElisaApplication::appHelpActivated() { QDesktopServices::openUrl(QUrl(QStringLiteral("help:/"))); } void ElisaApplication::aboutApplication() { #if defined KF5XmlGui_FOUND && KF5XmlGui_FOUND static QPointer dialog; if (!dialog) { dialog = new KAboutApplicationDialog(KAboutData::applicationData(), nullptr); dialog->setAttribute(Qt::WA_DeleteOnClose); } dialog->show(); #endif } void ElisaApplication::reportBug() { #if defined KF5XmlGui_FOUND && KF5XmlGui_FOUND static QPointer dialog; if (!dialog) { dialog = new KBugReport(KAboutData::applicationData(), nullptr); dialog->setAttribute(Qt::WA_DeleteOnClose); } dialog->show(); #endif } void ElisaApplication::configureShortcuts() { #if defined KF5XmlGui_FOUND && KF5XmlGui_FOUND KShortcutsDialog dlg(KShortcutsEditor::AllActions, KShortcutsEditor::LetterShortcutsAllowed, nullptr); dlg.setModal(true); dlg.addCollection(&d->mCollection); dlg.configure(); #endif } void ElisaApplication::configureElisa() { #if defined KF5KCMUtils_FOUND && KF5KCMUtils_FOUND KCMultiDialog configurationDialog; configurationDialog.addModule(QStringLiteral("kcm_elisa_local_file")); configurationDialog.setModal(true); configurationDialog.exec(); #endif } void ElisaApplication::goBack() {} void ElisaApplication::find() {} void ElisaApplication::togglePlaylist() {} void ElisaApplication::seek() {} void ElisaApplication::scrub() {} void ElisaApplication::playPause() {} ElisaUtils::EntryDataList ElisaApplication::checkFileListAndMakeAbsolute(const ElisaUtils::EntryDataList &filesList, const QString &workingDirectory) const { auto filesToOpen = ElisaUtils::EntryDataList{}; for (const auto &oneFile : filesList) { auto newFile = QFileInfo(std::get<1>(oneFile)); if (newFile.isRelative()) { newFile = QFileInfo(workingDirectory + QStringLiteral("/") + std::get<1>(oneFile)); } if (newFile.exists()) { filesToOpen.push_back(ElisaUtils::EntryData{0, newFile.canonicalFilePath()}); } } return filesToOpen; } void ElisaApplication::initialize() { initializeModels(); initializePlayer(); Q_EMIT initializationDone(); } void ElisaApplication::initializeModels() { d->mMusicManager = std::make_unique(); Q_EMIT musicManagerChanged(); d->mMediaPlayList = std::make_unique(); Q_EMIT mediaPlayListChanged(); d->mMusicManager->setElisaApplication(this); d->mMediaPlayList->setMusicListenersManager(d->mMusicManager.get()); QObject::connect(this, &ElisaApplication::enqueue, d->mMediaPlayList.get(), static_cast(&MediaPlayList::enqueue)); } void ElisaApplication::initializePlayer() { d->mAudioWrapper = std::make_unique(); Q_EMIT audioPlayerChanged(); d->mAudioControl = std::make_unique(); Q_EMIT audioControlChanged(); d->mPlayerControl = std::make_unique(); Q_EMIT playerControlChanged(); d->mManageHeaderBar = std::make_unique(); Q_EMIT manageHeaderBarChanged(); d->mAudioControl->setAlbumNameRole(MediaPlayList::AlbumRole); d->mAudioControl->setArtistNameRole(MediaPlayList::ArtistRole); d->mAudioControl->setTitleRole(MediaPlayList::TitleRole); d->mAudioControl->setUrlRole(MediaPlayList::ResourceRole); d->mAudioControl->setIsPlayingRole(MediaPlayList::IsPlayingRole); d->mAudioControl->setPlayListModel(d->mMediaPlayList.get()); QObject::connect(d->mAudioControl.get(), &ManageAudioPlayer::playerPlay, d->mAudioWrapper.get(), &AudioWrapper::play); QObject::connect(d->mAudioControl.get(), &ManageAudioPlayer::playerPause, d->mAudioWrapper.get(), &AudioWrapper::pause); QObject::connect(d->mAudioControl.get(), &ManageAudioPlayer::playerStop, d->mAudioWrapper.get(), &AudioWrapper::stop); QObject::connect(d->mAudioControl.get(), &ManageAudioPlayer::seek, d->mAudioWrapper.get(), &AudioWrapper::seek); QObject::connect(d->mAudioControl.get(), &ManageAudioPlayer::saveUndoPositionInAudioWrapper, d->mAudioWrapper.get(), &AudioWrapper::saveUndoPosition); QObject::connect(d->mAudioControl.get(), &ManageAudioPlayer::restoreUndoPositionInAudioWrapper, d->mAudioWrapper.get(), &AudioWrapper::restoreUndoPosition); QObject::connect(d->mAudioControl.get(), &ManageAudioPlayer::skipNextTrack, d->mMediaPlayList.get(), &MediaPlayList::skipNextTrack); QObject::connect(d->mAudioControl.get(), &ManageAudioPlayer::sourceInError, d->mMediaPlayList.get(), &MediaPlayList::trackInError); QObject::connect(d->mAudioControl.get(), &ManageAudioPlayer::sourceInError, d->mMusicManager.get(), &MusicListenersManager::playBackError); QObject::connect(d->mAudioControl.get(), &ManageAudioPlayer::playerSourceChanged, d->mAudioWrapper.get(), &AudioWrapper::setSource); QObject::connect(d->mAudioControl.get(), &ManageAudioPlayer::startedPlayingTrack, d->mMusicManager->viewDatabase(), &DatabaseInterface::trackHasStartedPlaying); QObject::connect(d->mMediaPlayList.get(), &MediaPlayList::ensurePlay, d->mAudioControl.get(), &ManageAudioPlayer::ensurePlay); QObject::connect(d->mMediaPlayList.get(), &MediaPlayList::playListFinished, d->mAudioControl.get(), &ManageAudioPlayer::playListFinished); QObject::connect(d->mMediaPlayList.get(), &MediaPlayList::currentTrackChanged, d->mAudioControl.get(), &ManageAudioPlayer::setCurrentTrack); QObject::connect(d->mMediaPlayList.get(), &MediaPlayList::clearPlayListPlayer, d->mAudioControl.get(), &ManageAudioPlayer::saveForUndoClearPlaylist); QObject::connect(d->mMediaPlayList.get(), &MediaPlayList::undoClearPlayListPlayer, d->mAudioControl.get(), &ManageAudioPlayer::restoreForUndoClearPlaylist); QObject::connect(d->mAudioWrapper.get(), &AudioWrapper::playbackStateChanged, d->mAudioControl.get(), &ManageAudioPlayer::setPlayerPlaybackState); QObject::connect(d->mAudioWrapper.get(), &AudioWrapper::statusChanged, d->mAudioControl.get(), &ManageAudioPlayer::setPlayerStatus); QObject::connect(d->mAudioWrapper.get(), &AudioWrapper::errorChanged, d->mAudioControl.get(), &ManageAudioPlayer::setPlayerError); QObject::connect(d->mAudioWrapper.get(), &AudioWrapper::durationChanged, d->mAudioControl.get(), &ManageAudioPlayer::setAudioDuration); QObject::connect(d->mAudioWrapper.get(), &AudioWrapper::seekableChanged, d->mAudioControl.get(), &ManageAudioPlayer::setPlayerIsSeekable); QObject::connect(d->mAudioWrapper.get(), &AudioWrapper::positionChanged, d->mAudioControl.get(), &ManageAudioPlayer::setPlayerPosition); d->mPlayerControl->setPlayListModel(d->mMediaPlayList.get()); QObject::connect(d->mMediaPlayList.get(), &MediaPlayList::currentTrackChanged, d->mPlayerControl.get(), &ManageMediaPlayerControl::setCurrentTrack); QObject::connect(d->mAudioWrapper.get(), &AudioWrapper::playing, d->mPlayerControl.get(), &ManageMediaPlayerControl::playerPlaying); QObject::connect(d->mAudioWrapper.get(), &AudioWrapper::paused, d->mPlayerControl.get(), &ManageMediaPlayerControl::playerPaused); QObject::connect(d->mAudioWrapper.get(), &AudioWrapper::stopped, d->mPlayerControl.get(), &ManageMediaPlayerControl::playerStopped); d->mManageHeaderBar->setTitleRole(MediaPlayList::TitleRole); d->mManageHeaderBar->setAlbumRole(MediaPlayList::AlbumRole); d->mManageHeaderBar->setAlbumArtistRole(MediaPlayList::AlbumArtistRole); d->mManageHeaderBar->setArtistRole(MediaPlayList::ArtistRole); + d->mManageHeaderBar->setFileNameRole(MediaPlayList::ResourceRole); d->mManageHeaderBar->setImageRole(MediaPlayList::ImageUrlRole); d->mManageHeaderBar->setDatabaseIdRole(MediaPlayList::DatabaseIdRole); d->mManageHeaderBar->setAlbumIdRole(MediaPlayList::AlbumIdRole); d->mManageHeaderBar->setIsValidRole(MediaPlayList::IsValidRole); d->mManageHeaderBar->setPlayListModel(d->mMediaPlayList.get()); QObject::connect(d->mMediaPlayList.get(), &MediaPlayList::currentTrackChanged, d->mManageHeaderBar.get(), &ManageHeaderBar::setCurrentTrack); if (!d->mArguments.isEmpty()) { Q_EMIT enqueue(d->mArguments, ElisaUtils::FileName, ElisaUtils::PlayListEnqueueMode::AppendPlayList, ElisaUtils::PlayListEnqueueTriggerPlay::TriggerPlay); } } QAction * ElisaApplication::action(const QString& name) { #if defined KF5XmlGui_FOUND && KF5XmlGui_FOUND auto resultAction = d->mCollection.action(name); if (!resultAction) { setupActions(name); resultAction = d->mCollection.action(name); } return resultAction; #else Q_UNUSED(name); return new QAction(); #endif } QString ElisaApplication::iconName(const QIcon& icon) { return icon.name(); } void ElisaApplication::installKeyEventFilter(QObject *object) { if(!object) { return; } object->installEventFilter(this); } bool ElisaApplication::eventFilter(QObject *object, QEvent *event) { Q_UNUSED(object); QKeyEvent *keyEvent = static_cast(event); auto playPauseAction = d->mCollection.action(tr("Play-Pause")); if (keyEvent->key() == Qt::Key_Space && playPauseAction->shortcut()[0] == Qt::Key_Space) { return true; } return false; } const ElisaUtils::EntryDataList &ElisaApplication::arguments() const { return d->mArguments; } MusicListenersManager *ElisaApplication::musicManager() const { return d->mMusicManager.get(); } MediaPlayList *ElisaApplication::mediaPlayList() const { return d->mMediaPlayList.get(); } AudioWrapper *ElisaApplication::audioPlayer() const { return d->mAudioWrapper.get(); } ManageAudioPlayer *ElisaApplication::audioControl() const { return d->mAudioControl.get(); } ManageMediaPlayerControl *ElisaApplication::playerControl() const { return d->mPlayerControl.get(); } ManageHeaderBar *ElisaApplication::manageHeaderBar() const { return d->mManageHeaderBar.get(); } #include "moc_elisaapplication.cpp" diff --git a/src/manageheaderbar.cpp b/src/manageheaderbar.cpp index 53e09eff..e2519074 100644 --- a/src/manageheaderbar.cpp +++ b/src/manageheaderbar.cpp @@ -1,489 +1,534 @@ /* * 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 . */ #include "manageheaderbar.h" #include #include #include #include ManageHeaderBar::ManageHeaderBar(QObject *parent) : QObject(parent) { } void ManageHeaderBar::setArtistRole(int value) { mArtistRole = value; Q_EMIT artistRoleChanged(); } int ManageHeaderBar::artistRole() const { return mArtistRole; } void ManageHeaderBar::setTitleRole(int value) { mTitleRole = value; Q_EMIT titleRoleChanged(); } int ManageHeaderBar::titleRole() const { return mTitleRole; } void ManageHeaderBar::setAlbumRole(int value) { mAlbumRole = value; Q_EMIT albumRoleChanged(); } void ManageHeaderBar::setAlbumArtistRole(int value) { mAlbumArtistRole = value; Q_EMIT albumArtistRoleChanged(); } +void ManageHeaderBar::setFileNameRole(int value) +{ + mFileNameRole = value; + Q_EMIT fileNameRoleChanged(); +} + int ManageHeaderBar::albumRole() const { return mAlbumRole; } int ManageHeaderBar::albumArtistRole() const { return mAlbumArtistRole; } +int ManageHeaderBar::fileNameRole() const +{ + return mFileNameRole; +} + void ManageHeaderBar::setImageRole(int value) { mImageRole = value; Q_EMIT imageRoleChanged(); } void ManageHeaderBar::setDatabaseIdRole(int databaseIdRole) { mDatabaseIdRole = databaseIdRole; Q_EMIT databaseIdRoleChanged(); } int ManageHeaderBar::imageRole() const { return mImageRole; } int ManageHeaderBar::databaseIdRole() const { return mDatabaseIdRole; } void ManageHeaderBar::setAlbumIdRole(int albumIdRole) { mAlbumIdRole = albumIdRole; Q_EMIT albumIdRoleChanged(); } int ManageHeaderBar::albumIdRole() const { return mAlbumIdRole; } QVariant ManageHeaderBar::album() const { if (!mCurrentTrack.isValid()) { return QString(); } return mCurrentTrack.data(mAlbumRole); } QVariant ManageHeaderBar::albumArtist() const { if (!mCurrentTrack.isValid()) { return QString(); } return mCurrentTrack.data(mAlbumArtistRole); } +QString ManageHeaderBar::fileName() const +{ + QString result; + + if (!mCurrentTrack.isValid()) { + return result; + } + + auto fileNameUrl = mCurrentTrack.data(mFileNameRole).toUrl(); + if (fileNameUrl.isLocalFile()) { + result = fileNameUrl.toLocalFile(); + } else { + result = fileNameUrl.toString(); + } + + return result; +} + QVariant ManageHeaderBar::title() const { if (!mCurrentTrack.isValid()) { return QString(); } return mCurrentTrack.data(mTitleRole); } QVariant ManageHeaderBar::artist() const { if (!mCurrentTrack.isValid()) { return QString(); } return mCurrentTrack.data(mArtistRole); } QUrl ManageHeaderBar::image() const { if (!mCurrentTrack.isValid()) { return {}; } return mCurrentTrack.data(mImageRole).toUrl(); } qulonglong ManageHeaderBar::databaseId() const { if (!mCurrentTrack.isValid()) { return 0; } return mCurrentTrack.data(mDatabaseIdRole).toULongLong(); } qulonglong ManageHeaderBar::albumId() const { if (!mCurrentTrack.isValid()) { return 0; } return mCurrentTrack.data(mAlbumIdRole).toULongLong(); } bool ManageHeaderBar::isValid() const { if (!mCurrentTrack.isValid()) { return false; } return mCurrentTrack.data(mIsValidRole).toBool(); } int ManageHeaderBar::remainingTracks() const { if (!mCurrentTrack.isValid()) { return 0; } return mPlayListModel->rowCount(mCurrentTrack.parent()) - mCurrentTrack.row() - 1; } int ManageHeaderBar::isValidRole() const { return mIsValidRole; } QPersistentModelIndex ManageHeaderBar::currentTrack() const { return mCurrentTrack; } void ManageHeaderBar::playListLayoutChanged(const QList &parents, QAbstractItemModel::LayoutChangeHint hint) { Q_UNUSED(parents); Q_UNUSED(hint); qDebug() << "ManageHeaderBar::playListLayoutChanged" << "not implemented"; } void ManageHeaderBar::tracksInserted(const QModelIndex &parent, int first, int last) { Q_UNUSED(parent); Q_UNUSED(first); Q_UNUSED(last); if (!mCurrentTrack.isValid()) { return; } if (mCurrentTrack.row() >= first) { return; } Q_EMIT remainingTracksChanged(); mOldRemainingTracks = remainingTracks(); } void ManageHeaderBar::tracksDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles) { if (!mCurrentTrack.isValid()) { return; } if (mCurrentTrack.row() > bottomRight.row() || mCurrentTrack.row() < topLeft.row()) { return; } if (mCurrentTrack.column() > bottomRight.column() || mCurrentTrack.column() < topLeft.column()) { return; } if (roles.isEmpty()) { notifyArtistProperty(); notifyTitleProperty(); notifyAlbumProperty(); notifyAlbumArtistProperty(); + notifyFileNameProperty(); notifyImageProperty(); notifyDatabaseIdProperty(); notifyAlbumIdProperty(); notifyIsValidProperty(); } else { for(auto oneRole : roles) { if (oneRole == mArtistRole) { notifyArtistProperty(); } if (oneRole == mTitleRole) { notifyTitleProperty(); } if (oneRole == mAlbumRole) { notifyAlbumProperty(); } if (oneRole == mAlbumArtistRole) { notifyAlbumArtistProperty(); } + if (oneRole == mFileNameRole) { + notifyFileNameProperty(); + } if (oneRole == mImageRole) { notifyImageProperty(); } if (oneRole == mDatabaseIdRole) { notifyDatabaseIdProperty(); } if (oneRole == mAlbumIdRole) { notifyAlbumIdProperty(); } if (oneRole == mIsValidRole) { notifyIsValidProperty(); } } } } void ManageHeaderBar::tracksAboutToBeMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row) { Q_UNUSED(parent); Q_UNUSED(start); Q_UNUSED(end); Q_UNUSED(destination); Q_UNUSED(row); mOldRemainingTracks = remainingTracks(); } void ManageHeaderBar::tracksMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row) { Q_UNUSED(parent); Q_UNUSED(start); Q_UNUSED(end); Q_UNUSED(destination); Q_UNUSED(row); auto newRemainingTracks = remainingTracks(); if (mOldRemainingTracks != newRemainingTracks) { Q_EMIT remainingTracksChanged(); } } void ManageHeaderBar::tracksRemoved(const QModelIndex &parent, int first, int last) { Q_UNUSED(parent); Q_UNUSED(first); Q_UNUSED(last); if (!mCurrentTrack.isValid()) { notifyArtistProperty(); notifyTitleProperty(); notifyAlbumProperty(); notifyAlbumArtistProperty(); + notifyFileNameProperty(); notifyImageProperty(); notifyDatabaseIdProperty(); notifyAlbumIdProperty(); notifyIsValidProperty(); notifyRemainingTracksProperty(); return; } notifyRemainingTracksProperty(); } void ManageHeaderBar::notifyArtistProperty() { auto newArtistValue = mCurrentTrack.data(mArtistRole); if (mOldArtist != newArtistValue) { Q_EMIT artistChanged(); mOldArtist = newArtistValue; } } void ManageHeaderBar::notifyTitleProperty() { auto newTitleValue = mCurrentTrack.data(mTitleRole); if (mOldTitle != newTitleValue) { Q_EMIT titleChanged(); mOldTitle = newTitleValue; } } void ManageHeaderBar::notifyAlbumProperty() { auto newAlbumValue = mCurrentTrack.data(mAlbumRole); if (mOldAlbum != newAlbumValue) { Q_EMIT albumChanged(); mOldAlbum = newAlbumValue; } } void ManageHeaderBar::notifyAlbumArtistProperty() { auto newAlbumArtistValue = mCurrentTrack.data(mAlbumArtistRole); if (mOldAlbumArtist != newAlbumArtistValue) { Q_EMIT albumArtistChanged(); mOldAlbumArtist = newAlbumArtistValue; } } +void ManageHeaderBar::notifyFileNameProperty() +{ + auto newFileNameValue = mCurrentTrack.data(mFileNameRole); + if (mOldFileName != newFileNameValue) { + Q_EMIT fileNameChanged(); + + mOldFileName = newFileNameValue; + } +} + void ManageHeaderBar::notifyImageProperty() { auto newImageValue = mCurrentTrack.data(mImageRole); if (mOldImage != newImageValue) { Q_EMIT imageChanged(); mOldImage = newImageValue; } } void ManageHeaderBar::notifyDatabaseIdProperty() { bool conversionOk; auto newDatabaseIdValue = mCurrentTrack.data(mDatabaseIdRole).toULongLong(&conversionOk); if (conversionOk && mOldDatabaseId != newDatabaseIdValue) { Q_EMIT databaseIdChanged(); mOldDatabaseId = newDatabaseIdValue; } else if (!conversionOk && mOldDatabaseId != 0) { Q_EMIT databaseIdChanged(); mOldDatabaseId = 0; } } void ManageHeaderBar::notifyAlbumIdProperty() { bool conversionOk; auto newAlbumIdValue = mCurrentTrack.data(mAlbumIdRole).toULongLong(&conversionOk); if (conversionOk && mOldAlbumId != newAlbumIdValue) { Q_EMIT albumIdChanged(); mOldAlbumId = newAlbumIdValue; } else if (!conversionOk && mOldAlbumId != 0) { Q_EMIT albumIdChanged(); mOldAlbumId = 0; } } void ManageHeaderBar::notifyIsValidProperty() { auto newIsValidValue = mCurrentTrack.data(mIsValidRole).toBool(); if (mOldIsValid != newIsValidValue) { Q_EMIT isValidChanged(); mOldIsValid = newIsValidValue; } } void ManageHeaderBar::notifyRemainingTracksProperty() { auto newRemainingTracksValue = remainingTracks(); if (mOldRemainingTracks != newRemainingTracksValue) { Q_EMIT remainingTracksChanged(); mOldRemainingTracks = newRemainingTracksValue; } } void ManageHeaderBar::setIsValidRole(int isValidRole) { mIsValidRole = isValidRole; emit isValidRoleChanged(); } void ManageHeaderBar::setCurrentTrack(const QPersistentModelIndex ¤tTrack) { if (mCurrentTrack == currentTrack) { return; } auto oldRemainingTracksCount = remainingTracks(); mCurrentTrack = currentTrack; Q_EMIT currentTrackChanged(); if (mCurrentTrack.isValid() && oldRemainingTracksCount != remainingTracks()) { Q_EMIT remainingTracksChanged(); mOldRemainingTracks = remainingTracks(); } notifyArtistProperty(); notifyTitleProperty(); notifyAlbumProperty(); notifyAlbumArtistProperty(); + notifyFileNameProperty(); notifyImageProperty(); notifyDatabaseIdProperty(); notifyAlbumIdProperty(); notifyIsValidProperty(); } void ManageHeaderBar::setPlayListModel(QAbstractItemModel *aPlayListModel) { if (mPlayListModel) { disconnect(mPlayListModel, &QAbstractItemModel::rowsInserted, this, &ManageHeaderBar::tracksInserted); disconnect(mPlayListModel, &QAbstractItemModel::rowsAboutToBeMoved, this, &ManageHeaderBar::tracksAboutToBeMoved); disconnect(mPlayListModel, &QAbstractItemModel::rowsMoved, this, &ManageHeaderBar::tracksMoved); disconnect(mPlayListModel, &QAbstractItemModel::rowsRemoved, this, &ManageHeaderBar::tracksRemoved); disconnect(mPlayListModel, &QAbstractItemModel::dataChanged, this, &ManageHeaderBar::tracksDataChanged); disconnect(mPlayListModel, &QAbstractItemModel::layoutChanged, this, &ManageHeaderBar::playListLayoutChanged); } mPlayListModel = aPlayListModel; if (mPlayListModel) { connect(mPlayListModel, &QAbstractItemModel::rowsInserted, this, &ManageHeaderBar::tracksInserted); connect(mPlayListModel, &QAbstractItemModel::rowsAboutToBeMoved, this, &ManageHeaderBar::tracksAboutToBeMoved); connect(mPlayListModel, &QAbstractItemModel::rowsMoved, this, &ManageHeaderBar::tracksMoved); connect(mPlayListModel, &QAbstractItemModel::rowsRemoved, this, &ManageHeaderBar::tracksRemoved); connect(mPlayListModel, &QAbstractItemModel::dataChanged, this, &ManageHeaderBar::tracksDataChanged); connect(mPlayListModel, &QAbstractItemModel::layoutChanged, this, &ManageHeaderBar::playListLayoutChanged); } Q_EMIT playListModelChanged(); } QAbstractItemModel *ManageHeaderBar::playListModel() const { return mPlayListModel; } #include "moc_manageheaderbar.cpp" diff --git a/src/manageheaderbar.h b/src/manageheaderbar.h index 9aa6e26a..a9ad5a0d 100644 --- a/src/manageheaderbar.h +++ b/src/manageheaderbar.h @@ -1,298 +1,323 @@ /* * 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 . */ #ifndef MANAGEHEADERBAR_H #define MANAGEHEADERBAR_H #include "elisaLib_export.h" #include #include #include #include #include #include class ELISALIB_EXPORT ManageHeaderBar : public QObject { Q_OBJECT Q_PROPERTY(QPersistentModelIndex currentTrack READ currentTrack WRITE setCurrentTrack NOTIFY currentTrackChanged) Q_PROPERTY(QAbstractItemModel* playListModel READ playListModel WRITE setPlayListModel NOTIFY playListModelChanged) Q_PROPERTY(int artistRole READ artistRole WRITE setArtistRole NOTIFY artistRoleChanged) Q_PROPERTY(int titleRole READ titleRole WRITE setTitleRole NOTIFY titleRoleChanged) Q_PROPERTY(int albumRole READ albumRole WRITE setAlbumRole NOTIFY albumRoleChanged) Q_PROPERTY(int albumArtistRole READ albumArtistRole WRITE setAlbumArtistRole NOTIFY albumArtistRoleChanged) + Q_PROPERTY(int fileNameRole + READ fileNameRole + WRITE setFileNameRole + NOTIFY fileNameRoleChanged) + Q_PROPERTY(int imageRole READ imageRole WRITE setImageRole NOTIFY imageRoleChanged) Q_PROPERTY(int databaseIdRole READ databaseIdRole WRITE setDatabaseIdRole NOTIFY databaseIdRoleChanged) Q_PROPERTY(int albumIdRole READ albumIdRole WRITE setAlbumIdRole NOTIFY albumIdRoleChanged) Q_PROPERTY(int isValidRole READ isValidRole WRITE setIsValidRole NOTIFY isValidRoleChanged) Q_PROPERTY(QVariant artist READ artist NOTIFY artistChanged) Q_PROPERTY(QVariant title READ title NOTIFY titleChanged) Q_PROPERTY(QVariant album READ album NOTIFY albumChanged) Q_PROPERTY(QVariant albumArtist READ albumArtist NOTIFY albumArtistChanged) + Q_PROPERTY(QString fileName + READ fileName + NOTIFY fileNameChanged) + Q_PROPERTY(QUrl image READ image NOTIFY imageChanged) Q_PROPERTY(qulonglong databaseId READ databaseId NOTIFY databaseIdChanged) Q_PROPERTY(qulonglong albumId READ albumId NOTIFY albumIdChanged) Q_PROPERTY(bool isValid READ isValid NOTIFY isValidChanged) Q_PROPERTY(int remainingTracks READ remainingTracks NOTIFY remainingTracksChanged) public: explicit ManageHeaderBar(QObject *parent = nullptr); QPersistentModelIndex currentTrack() const; QAbstractItemModel* playListModel() const; int artistRole() const; int titleRole() const; int albumRole() const; int albumArtistRole() const; + int fileNameRole() const; + int imageRole() const; int databaseIdRole() const; int albumIdRole() const; int isValidRole() const; QVariant artist() const; QVariant title() const; QVariant album() const; QVariant albumArtist() const; + QString fileName() const; + QUrl image() const; qulonglong databaseId() const; qulonglong albumId() const; bool isValid() const; int remainingTracks() const; Q_SIGNALS: void currentTrackChanged(); void playListModelChanged(); void artistRoleChanged(); void titleRoleChanged(); void albumRoleChanged(); void albumArtistRoleChanged(); + void fileNameRoleChanged(); + void imageRoleChanged(); void databaseIdRoleChanged(); void albumIdRoleChanged(); void isValidRoleChanged(); void artistChanged(); void titleChanged(); void albumChanged(); void albumArtistChanged(); + void fileNameChanged(); + void imageChanged(); void remainingTracksChanged(); void databaseIdChanged(); void albumIdChanged(); void isValidChanged(); public Q_SLOTS: void setCurrentTrack(const QPersistentModelIndex ¤tTrack); void setPlayListModel(QAbstractItemModel* aPlayListModel); void setArtistRole(int value); void setTitleRole(int value); void setAlbumRole(int value); void setAlbumArtistRole(int value); + void setFileNameRole(int value); + void setImageRole(int value); void setDatabaseIdRole(int databaseIdRole); void setAlbumIdRole(int albumIdRole); void setIsValidRole(int isValidRole); void playListLayoutChanged(const QList &parents, QAbstractItemModel::LayoutChangeHint hint); void tracksInserted(const QModelIndex &parent, int first, int last); void tracksDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles); void tracksAboutToBeMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row); void tracksMoved(const QModelIndex &parent, int start, int end, const QModelIndex &destination, int row); void tracksRemoved(const QModelIndex &parent, int first, int last); private: void notifyArtistProperty(); void notifyTitleProperty(); void notifyAlbumProperty(); void notifyAlbumArtistProperty(); + void notifyFileNameProperty(); + void notifyImageProperty(); void notifyDatabaseIdProperty(); void notifyAlbumIdProperty(); void notifyIsValidProperty(); void notifyRemainingTracksProperty(); QPersistentModelIndex mCurrentTrack; QAbstractItemModel *mPlayListModel = nullptr; int mArtistRole = Qt::DisplayRole; int mTitleRole = Qt::DisplayRole; int mAlbumRole = Qt::DisplayRole; int mAlbumArtistRole = Qt::DisplayRole; + int mFileNameRole = Qt::DisplayRole; + int mImageRole = Qt::DisplayRole; int mDatabaseIdRole = Qt::DisplayRole; int mAlbumIdRole = Qt::DisplayRole; int mIsValidRole = Qt::DisplayRole; QVariant mOldArtist; QVariant mOldTitle; QVariant mOldAlbum; QVariant mOldAlbumArtist; + QVariant mOldFileName; + QVariant mOldImage; qulonglong mOldDatabaseId = 0; qulonglong mOldAlbumId = 0; bool mOldIsValid = false; int mOldRemainingTracks = 0; }; #endif // MANAGEHEADERBAR_H diff --git a/src/qml/ContentView.qml b/src/qml/ContentView.qml index 5f2b88da..74755ede 100644 --- a/src/qml/ContentView.qml +++ b/src/qml/ContentView.qml @@ -1,568 +1,569 @@ /* * Copyright 2016-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.Layouts 1.2 import QtQuick.Window 2.2 import org.kde.elisa 1.0 RowLayout { id: contentViewContainer spacing: 0 property bool showPlaylist property alias currentViewIndex: listViews.currentIndex signal toggleSearch() function goBack() { viewManager.goBack() } function openArtist(name) { viewManager.openChildView(name, '', elisaTheme.artistIcon, 0, ElisaUtils.Artist) } function openAlbum(album, artist, image, albumID) { image = !image ? elisaTheme.defaultAlbumImage : image; viewManager.openChildView(album, artist, image, albumID, ElisaUtils.Album); } function openNowPlaying() { viewManager.closeAllViews(); // This is needed to trigger the state change listViews.currentIndex = 0; } ViewManager { id: viewManager onSwitchOffAllViews: { listViews.setCurrentIndex(pageModel.indexFromViewType(viewType)) while(browseStackView.depth > 1) { browseStackView.pop() } } onSwitchRecentlyPlayedTracksView: { listViews.setCurrentIndex(pageModel.indexFromViewType(viewType)) while(browseStackView.depth > expectedDepth) { browseStackView.pop() } browseStackView.push(allRecentlyPlayedTracksView, { viewType: viewType, mainTitle: mainTitle, image: imageUrl, modelType: dataType, stackView: browseStackView, opacity: 0, }) } onSwitchFrequentlyPlayedTracksView: { listViews.setCurrentIndex(pageModel.indexFromViewType(viewType)) while(browseStackView.depth > expectedDepth) { browseStackView.pop() } browseStackView.push(allFrequentlyPlayedTracksView, { viewType: viewType, mainTitle: mainTitle, image: imageUrl, modelType: dataType, stackView: browseStackView, opacity: 0, }) } onOpenGridView: { if (expectedDepth === 1) { listViews.setCurrentIndex(pageModel.indexFromViewType(viewType)) } while(browseStackView.depth > expectedDepth) { browseStackView.pop() } browseStackView.push(dataGridView, { viewType: viewType, mainTitle: pageModel.viewMainTitle(viewType, mainTitle), secondaryTitle: secondaryTitle, image: pageModel.viewImageUrl(viewType, imageUrl), modelType: dataType, defaultIcon: viewDefaultIcon, showRating: viewShowRating, delegateDisplaySecondaryText: viewDelegateDisplaySecondaryText, genreFilterText: genreNameFilter, artistFilter: artistNameFilter, isSubPage: (browseStackView.depth >= 2), stackView: browseStackView, opacity: 0, }) } onSwitchOneAlbumView: { while(browseStackView.depth > expectedDepth) { browseStackView.pop() } browseStackView.push(albumView, { viewType: viewType, mainTitle: mainTitle, secondaryTitle: secondaryTitle, image: imageUrl, databaseId: databaseId, stackView: browseStackView, opacity: 0, }) } onSwitchAllTracksView: { listViews.setCurrentIndex(pageModel.indexFromViewType(viewType)) while(browseStackView.depth > expectedDepth) { browseStackView.pop() } browseStackView.push(allTracksView, { viewType: viewType, mainTitle: mainTitle, image: imageUrl, modelType: dataType, stackView: browseStackView, opacity: 0, }) } onSwitchFilesBrowserView: { listViews.setCurrentIndex(pageModel.indexFromViewType(viewType)) while(browseStackView.depth > expectedDepth) { browseStackView.pop() } browseStackView.push(filesBrowserView, { viewType: viewType, mainTitle: mainTitle, image: imageUrl, opacity: 0, }) } onPopOneView: { browseStackView.pop() } } ViewsModel { id: pageModel } ViewSelector { id: listViews model: pageModel Layout.fillHeight: true Layout.maximumWidth: mainWindow.width * 0.14 maximumSize: mainWindow.width * 0.14 Behavior on Layout.maximumWidth { NumberAnimation { duration: 150 } } onSwitchView: viewManager.openParentView(viewType, pageModel.viewMainTitle(viewType, ""), pageModel.viewImageUrl(viewType, "")) } Rectangle { id: viewSelectorSeparatorItem border.width: 1 border.color: myPalette.mid color: myPalette.mid visible: true Layout.bottomMargin: elisaTheme.layoutVerticalMargin Layout.topMargin: elisaTheme.layoutVerticalMargin Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter Layout.fillHeight: true Layout.preferredWidth: 1 Layout.minimumWidth: 1 Layout.maximumWidth: 1 } ColumnLayout { Layout.fillHeight: true Layout.fillWidth: true spacing: 0 TopNotification { id: invalidBalooConfiguration Layout.fillWidth: true musicManager: elisa.musicManager focus: true } Item { Layout.fillHeight: true Layout.fillWidth: true RowLayout { anchors.fill: parent spacing: 0 id: contentZone FocusScope { id: mainContentView focus: true Layout.fillHeight: true Layout.minimumWidth: 0 Layout.maximumWidth: 0 Layout.preferredWidth: 0 visible: Layout.minimumWidth != 0 Rectangle { border { color: (mainContentView.activeFocus ? myPalette.highlight : myPalette.base) width: 1 } radius: 3 color: myPalette.base anchors.fill: parent StackView { id: browseStackView anchors.fill: parent clip: true initialItem: Item { } popEnter: Transition { OpacityAnimator { from: 0.0 to: 1.0 duration: 300 } } popExit: Transition { OpacityAnimator { from: 1.0 to: 0.0 duration: 300 } } pushEnter: Transition { OpacityAnimator { from: 0.0 to: 1.0 duration: 300 } } pushExit: Transition { OpacityAnimator { from: 1.0 to: 0.0 duration: 300 } } replaceEnter: Transition { OpacityAnimator { from: 0.0 to: 1.0 duration: 300 } } replaceExit: Transition { OpacityAnimator { from: 1.0 to: 0.0 duration: 300 } } } Behavior on border.color { ColorAnimation { duration: 300 } } } } Rectangle { id: firstViewSeparatorItem border.width: 1 border.color: myPalette.mid color: myPalette.mid visible: true Layout.bottomMargin: elisaTheme.layoutVerticalMargin Layout.topMargin: elisaTheme.layoutVerticalMargin Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter Layout.fillHeight: true Layout.preferredWidth: 1 Layout.minimumWidth: 1 Layout.maximumWidth: 1 } MediaPlayListView { id: playList Layout.fillHeight: true Layout.leftMargin: elisaTheme.layoutHorizontalMargin Layout.rightMargin: elisaTheme.layoutHorizontalMargin Layout.minimumWidth: contentZone.width Layout.maximumWidth: contentZone.width Layout.preferredWidth: contentZone.width onStartPlayback: elisa.audioControl.ensurePlay() onPausePlayback: elisa.audioControl.playPause() onDisplayError: messageNotification.showNotification(errorText) } Rectangle { id: viewSeparatorItem border.width: 1 border.color: myPalette.mid color: myPalette.mid visible: Layout.minimumWidth != 0 Layout.bottomMargin: elisaTheme.layoutVerticalMargin Layout.topMargin: elisaTheme.layoutVerticalMargin Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter Layout.fillHeight: true Layout.preferredWidth: 1 Layout.minimumWidth: 1 Layout.maximumWidth: 1 } Loader { id: albumContext active: Layout.minimumWidth != 0 sourceComponent: ContextView { anchors.fill: parent databaseId: elisa.manageHeaderBar.databaseId title: elisa.manageHeaderBar.title artistName: elisa.manageHeaderBar.artist albumName: elisa.manageHeaderBar.album albumArtUrl: elisa.manageHeaderBar.image + fileUrl: elisa.manageHeaderBar.fileName } Layout.fillHeight: true Layout.minimumWidth: contentZone.width Layout.maximumWidth: contentZone.width Layout.preferredWidth: contentZone.width Layout.leftMargin: elisaTheme.layoutHorizontalMargin * 3 visible: Layout.minimumWidth != 0 } } } states: [ State { name: 'playList' when: listViews.currentIndex === 0 PropertyChanges { target: mainContentView Layout.minimumWidth: 0 Layout.maximumWidth: 0 Layout.preferredWidth: 0 } PropertyChanges { target: firstViewSeparatorItem Layout.minimumWidth: 0 Layout.maximumWidth: 0 Layout.preferredWidth: 0 } PropertyChanges { target: playList Layout.minimumWidth: contentZone.width * 2 / 5 Layout.maximumWidth: contentZone.width * 2 / 5 Layout.preferredWidth: contentZone.width * 2 / 5 } PropertyChanges { target: viewSeparatorItem Layout.minimumWidth: 1 Layout.maximumWidth: 1 Layout.preferredWidth: 1 } PropertyChanges { target: albumContext Layout.minimumWidth: contentZone.width * 3 / 5 - 2 - 5 * elisaTheme.layoutHorizontalMargin Layout.maximumWidth: contentZone.width * 3 / 5 - 2 - 5 * elisaTheme.layoutHorizontalMargin Layout.preferredWidth: contentZone.width * 3 / 5 - 2 - 5 * elisaTheme.layoutHorizontalMargin } }, State { name: "browsingViewsNoPlaylist" when: listViews.currentIndex !== 0 && contentViewContainer.showPlaylist !== true extend: "browsingViews" PropertyChanges { target: mainContentView Layout.minimumWidth: contentZone.width Layout.maximumWidth: contentZone.width Layout.preferredWidth: contentZone.width } PropertyChanges { target: playList Layout.minimumWidth: 0 Layout.maximumWidth: 0 Layout.preferredWidth: 0 } }, State { name: 'browsingViews' when: listViews.currentIndex !== 0 PropertyChanges { target: mainContentView Layout.minimumWidth: contentZone.width * 0.66 Layout.maximumWidth: contentZone.width * 0.68 Layout.preferredWidth: contentZone.width * 0.68 } PropertyChanges { target: firstViewSeparatorItem Layout.minimumWidth: 1 Layout.maximumWidth: 1 Layout.preferredWidth: 1 } PropertyChanges { target: playList Layout.minimumWidth: contentZone.width * 0.33 - 3 * elisaTheme.layoutHorizontalMargin + 2 Layout.maximumWidth: contentZone.width * 0.33 - 3 * elisaTheme.layoutHorizontalMargin + 2 Layout.preferredWidth: contentZone.width * 0.33 - 3 * elisaTheme.layoutHorizontalMargin + 2 } PropertyChanges { target: viewSeparatorItem Layout.minimumWidth: 0 Layout.maximumWidth: 0 Layout.preferredWidth: 0 } PropertyChanges { target: albumContext Layout.minimumWidth: 0 Layout.maximumWidth: 0 Layout.preferredWidth: 0 } } ] transitions: Transition { NumberAnimation { properties: "Layout.minimumWidth, Layout.maximumWidth, Layout.preferredWidth, opacity" easing.type: Easing.InOutQuad duration: 300 } } } Component { id: allFrequentlyPlayedTracksView FrequentlyPlayedTracks { StackView.onActivated: viewManager.viewIsLoaded(viewType) } } Component { id: allRecentlyPlayedTracksView RecentlyPlayedTracks { StackView.onActivated: viewManager.viewIsLoaded(viewType) } } Component { id: dataGridView DataGridView { StackView.onActivated: viewManager.viewIsLoaded(viewType) } } Component { id: allTracksView TracksView { StackView.onActivated: viewManager.viewIsLoaded(viewType) } } Component { id: albumView AlbumView { StackView.onActivated: viewManager.viewIsLoaded(viewType) } } Component { id: filesBrowserView FileBrowserView { StackView.onActivated: viewManager.viewIsLoaded(viewType) } } } diff --git a/src/qml/ContextView.qml b/src/qml/ContextView.qml index 634cb6d7..6255c1c6 100644 --- a/src/qml/ContextView.qml +++ b/src/qml/ContextView.qml @@ -1,143 +1,167 @@ /* * 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: i18nc('display of artist and album in context view', 'by %1 from %2', artistName, albumName) font.pointSize: elisaTheme.defaultFontPointSize * 1.4 Layout.alignment: Qt.AlignLeft | Qt.AlignTop Layout.bottomMargin: elisaTheme.layoutVerticalMargin elide: Text.ElideRight } Repeater { model: metaDataModel delegate: MetaDataDelegate { } } 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) } } }