refactor(playlist): playlist itself as model
This could make state management easier, and also make it reusable just in case we need to attach the playlist to a view.
This commit is contained in:
parent
4a095a0cfd
commit
eb2e2e93f9
@ -46,7 +46,7 @@
|
|||||||
MainWindow::MainWindow(QWidget *parent)
|
MainWindow::MainWindow(QWidget *parent)
|
||||||
: FramelessWindow(parent)
|
: FramelessWindow(parent)
|
||||||
, m_am(new ActionManager)
|
, m_am(new ActionManager)
|
||||||
, m_pm(new PlaylistManager(PlaylistManager::PL_SAMEFOLDER, this))
|
, m_pm(new PlaylistManager(this))
|
||||||
{
|
{
|
||||||
if (Settings::instance()->stayOnTop()) {
|
if (Settings::instance()->stayOnTop()) {
|
||||||
this->setWindowFlag(Qt::WindowStaysOnTopHint);
|
this->setWindowFlag(Qt::WindowStaysOnTopHint);
|
||||||
@ -62,7 +62,7 @@ MainWindow::MainWindow(QWidget *parent)
|
|||||||
for (const QByteArray &item : QImageReader::supportedImageFormats()) {
|
for (const QByteArray &item : QImageReader::supportedImageFormats()) {
|
||||||
formatFilters.append(QStringLiteral("*.") % QString::fromLocal8Bit(item));
|
formatFilters.append(QStringLiteral("*.") % QString::fromLocal8Bit(item));
|
||||||
}
|
}
|
||||||
m_pm->setAutoLoadFilterSuffix(formatFilters);
|
m_pm->setAutoLoadFilterSuffixes(formatFilters);
|
||||||
|
|
||||||
m_fadeOutAnimation = new QPropertyAnimation(this, "windowOpacity");
|
m_fadeOutAnimation = new QPropertyAnimation(this, "windowOpacity");
|
||||||
m_fadeOutAnimation->setDuration(300);
|
m_fadeOutAnimation->setDuration(300);
|
||||||
@ -142,19 +142,12 @@ MainWindow::MainWindow(QWidget *parent)
|
|||||||
m_gv->setOpacity(0, false);
|
m_gv->setOpacity(0, false);
|
||||||
m_closeButton->setOpacity(0, false);
|
m_closeButton->setOpacity(0, false);
|
||||||
|
|
||||||
connect(m_pm, &PlaylistManager::loaded, this, [this](int galleryFileCount) {
|
connect(m_pm, &PlaylistManager::totalCountChanged, this, [this](int galleryFileCount) {
|
||||||
m_prevButton->setVisible(galleryFileCount > 1);
|
m_prevButton->setVisible(galleryFileCount > 1);
|
||||||
m_nextButton->setVisible(galleryFileCount > 1);
|
m_nextButton->setVisible(galleryFileCount > 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(m_pm, &PlaylistManager::currentIndexChanged, this, [this]() {
|
connect(m_pm, &PlaylistManager::currentIndexChanged, this, &MainWindow::galleryCurrent);
|
||||||
int index;
|
|
||||||
QUrl url;
|
|
||||||
std::tie(index, url) = m_pm->currentFileUrl();
|
|
||||||
if (index != -1) {
|
|
||||||
this->setWindowTitle(url.fileName());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
QShortcut * fullscreenShorucut = new QShortcut(QKeySequence(QKeySequence::FullScreen), this);
|
QShortcut * fullscreenShorucut = new QShortcut(QKeySequence(QKeySequence::FullScreen), this);
|
||||||
connect(fullscreenShorucut, &QShortcut::activated,
|
connect(fullscreenShorucut, &QShortcut::activated,
|
||||||
@ -187,7 +180,6 @@ void MainWindow::showUrls(const QList<QUrl> &urls)
|
|||||||
} else {
|
} else {
|
||||||
m_graphicsView->showFileFromPath(urls.first().toLocalFile(), false);
|
m_graphicsView->showFileFromPath(urls.first().toLocalFile(), false);
|
||||||
m_pm->setPlaylist(urls);
|
m_pm->setPlaylist(urls);
|
||||||
m_pm->setCurrentIndex(0);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
m_graphicsView->showText(tr("File url list is empty"));
|
m_graphicsView->showText(tr("File url list is empty"));
|
||||||
@ -214,7 +206,7 @@ void MainWindow::initWindowSize()
|
|||||||
|
|
||||||
void MainWindow::adjustWindowSizeBySceneRect()
|
void MainWindow::adjustWindowSizeBySceneRect()
|
||||||
{
|
{
|
||||||
if (m_pm->count() < 1) return;
|
if (m_pm->totalCount() < 1) return;
|
||||||
|
|
||||||
QSize sceneSize = m_graphicsView->sceneRect().toRect().size();
|
QSize sceneSize = m_graphicsView->sceneRect().toRect().size();
|
||||||
QSize sceneSizeWithMargins = sceneSize + QSize(130, 125);
|
QSize sceneSizeWithMargins = sceneSize + QSize(130, 125);
|
||||||
@ -245,42 +237,31 @@ void MainWindow::adjustWindowSizeBySceneRect()
|
|||||||
// can be empty if it is NOT from a local file.
|
// can be empty if it is NOT from a local file.
|
||||||
QUrl MainWindow::currentImageFileUrl() const
|
QUrl MainWindow::currentImageFileUrl() const
|
||||||
{
|
{
|
||||||
QUrl url;
|
return m_pm->urlByIndex(m_pm->curIndex());
|
||||||
std::tie(std::ignore, url) = m_pm->currentFileUrl();
|
|
||||||
|
|
||||||
return url;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::clearGallery()
|
void MainWindow::clearGallery()
|
||||||
{
|
{
|
||||||
m_pm->clear();
|
m_pm->setPlaylist({});
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::loadGalleryBySingleLocalFile(const QString &path)
|
void MainWindow::loadGalleryBySingleLocalFile(const QString &path)
|
||||||
{
|
{
|
||||||
m_pm->setCurrentFile(path);
|
m_pm->loadPlaylist({QUrl::fromLocalFile(path)});
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::galleryPrev()
|
void MainWindow::galleryPrev()
|
||||||
{
|
{
|
||||||
int index;
|
QModelIndex index = m_pm->previousIndex();
|
||||||
QString filePath;
|
if (index.isValid()) {
|
||||||
std::tie(index, filePath) = m_pm->previousFile();
|
|
||||||
|
|
||||||
if (index >= 0) {
|
|
||||||
m_graphicsView->showFileFromPath(filePath, false);
|
|
||||||
m_pm->setCurrentIndex(index);
|
m_pm->setCurrentIndex(index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::galleryNext()
|
void MainWindow::galleryNext()
|
||||||
{
|
{
|
||||||
int index;
|
QModelIndex index = m_pm->nextIndex();
|
||||||
QString filePath;
|
if (index.isValid()) {
|
||||||
std::tie(index, filePath) = m_pm->nextFile();
|
|
||||||
|
|
||||||
if (index >= 0) {
|
|
||||||
m_graphicsView->showFileFromPath(filePath, false);
|
|
||||||
m_pm->setCurrentIndex(index);
|
m_pm->setCurrentIndex(index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -288,12 +269,10 @@ void MainWindow::galleryNext()
|
|||||||
// If playlist (or its index) get changed, use this method to "reload" the current file.
|
// If playlist (or its index) get changed, use this method to "reload" the current file.
|
||||||
void MainWindow::galleryCurrent()
|
void MainWindow::galleryCurrent()
|
||||||
{
|
{
|
||||||
int index;
|
QModelIndex index = m_pm->curIndex();
|
||||||
QString filePath;
|
if (index.isValid()) {
|
||||||
std::tie(index, filePath) = m_pm->currentFile();
|
setWindowTitle(m_pm->urlByIndex(index).fileName());
|
||||||
|
m_graphicsView->showFileFromPath(m_pm->localFileByIndex(index), false);
|
||||||
if (index >= 0) {
|
|
||||||
m_graphicsView->showFileFromPath(filePath, false);
|
|
||||||
} else {
|
} else {
|
||||||
m_graphicsView->showText(QCoreApplication::translate("GraphicsScene", "Drag image here"));
|
m_graphicsView->showText(QCoreApplication::translate("GraphicsScene", "Drag image here"));
|
||||||
}
|
}
|
||||||
@ -721,18 +700,16 @@ void MainWindow::on_actionPaste_triggered()
|
|||||||
} else if (clipboardFileUrl.isValid()) {
|
} else if (clipboardFileUrl.isValid()) {
|
||||||
QString localFile(clipboardFileUrl.toLocalFile());
|
QString localFile(clipboardFileUrl.toLocalFile());
|
||||||
m_graphicsView->showFileFromPath(localFile, true);
|
m_graphicsView->showFileFromPath(localFile, true);
|
||||||
m_pm->setCurrentFile(localFile);
|
m_pm->loadPlaylist({clipboardFileUrl});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_actionTrash_triggered()
|
void MainWindow::on_actionTrash_triggered()
|
||||||
{
|
{
|
||||||
int currentFileIndex;
|
QModelIndex index = m_pm->curIndex();
|
||||||
QUrl currentFileUrl;
|
if (!m_pm->urlByIndex(index).isLocalFile()) return;
|
||||||
std::tie(currentFileIndex, currentFileUrl) = m_pm->currentFileUrl();
|
|
||||||
if (!currentFileUrl.isLocalFile()) return;
|
|
||||||
|
|
||||||
QFile file(currentFileUrl.toLocalFile());
|
QFile file(m_pm->localFileByIndex(index));
|
||||||
QFileInfo fileInfo(file.fileName());
|
QFileInfo fileInfo(file.fileName());
|
||||||
|
|
||||||
QMessageBox::StandardButton result = QMessageBox::question(this, tr("Move to Trash"),
|
QMessageBox::StandardButton result = QMessageBox::question(this, tr("Move to Trash"),
|
||||||
@ -743,7 +720,7 @@ void MainWindow::on_actionTrash_triggered()
|
|||||||
QMessageBox::warning(this, "Failed to move file to trash",
|
QMessageBox::warning(this, "Failed to move file to trash",
|
||||||
tr("Move to trash failed, it might caused by file permission issue, file system limitation, or platform limitation."));
|
tr("Move to trash failed, it might caused by file permission issue, file system limitation, or platform limitation."));
|
||||||
} else {
|
} else {
|
||||||
m_pm->removeFileAt(currentFileIndex);
|
m_pm->removeAt(index);
|
||||||
galleryCurrent();
|
galleryCurrent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// SPDX-FileCopyrightText: 2022 Gary Wang <wzc782970009@gmail.com>
|
// SPDX-FileCopyrightText: 2024 Gary Wang <git@blumia.net>
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
@ -9,166 +9,222 @@
|
|||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
|
||||||
PlaylistManager::PlaylistManager(PlaylistType type, QObject *parent)
|
PlaylistModel::PlaylistModel(QObject *parent)
|
||||||
: QObject(parent)
|
: QAbstractListModel(parent)
|
||||||
, m_type(type)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PlaylistModel::~PlaylistModel()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlaylistModel::setPlaylist(const QList<QUrl> &urls)
|
||||||
|
{
|
||||||
|
beginResetModel();
|
||||||
|
m_playlist = urls;
|
||||||
|
endResetModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex PlaylistModel::loadPlaylist(const QList<QUrl> & urls)
|
||||||
|
{
|
||||||
|
if (urls.isEmpty()) return QModelIndex();
|
||||||
|
if (urls.count() == 1) {
|
||||||
|
return loadPlaylist(urls.constFirst());
|
||||||
|
} else {
|
||||||
|
setPlaylist(urls);
|
||||||
|
return createIndex(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex PlaylistModel::loadPlaylist(const QUrl &url)
|
||||||
|
{
|
||||||
|
QFileInfo info(url.toLocalFile());
|
||||||
|
QDir dir(info.path());
|
||||||
|
QString && currentFileName = info.fileName();
|
||||||
|
|
||||||
|
if (dir.path() == m_currentDir) {
|
||||||
|
int index = indexOf(url);
|
||||||
|
return index == -1 ? appendToPlaylist(url) : createIndex(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList entryList = dir.entryList(
|
||||||
|
m_autoLoadSuffixes,
|
||||||
|
QDir::Files | QDir::NoSymLinks, QDir::NoSort);
|
||||||
|
|
||||||
|
QCollator collator;
|
||||||
|
collator.setNumericMode(true);
|
||||||
|
|
||||||
|
std::sort(entryList.begin(), entryList.end(), collator);
|
||||||
|
|
||||||
|
QList<QUrl> playlist;
|
||||||
|
|
||||||
|
int index = -1;
|
||||||
|
for (int i = 0; i < entryList.count(); i++) {
|
||||||
|
const QString & fileName = entryList.at(i);
|
||||||
|
const QString & oneEntry = dir.absoluteFilePath(fileName);
|
||||||
|
const QUrl & url = QUrl::fromLocalFile(oneEntry);
|
||||||
|
playlist.append(url);
|
||||||
|
if (fileName == currentFileName) {
|
||||||
|
index = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (index == -1) {
|
||||||
|
index = playlist.count();
|
||||||
|
playlist.append(url);
|
||||||
|
}
|
||||||
|
m_currentDir = dir.path();
|
||||||
|
|
||||||
|
setPlaylist(playlist);
|
||||||
|
|
||||||
|
return createIndex(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex PlaylistModel::appendToPlaylist(const QUrl &url)
|
||||||
|
{
|
||||||
|
const int lastIndex = rowCount();
|
||||||
|
beginInsertRows(QModelIndex(), lastIndex, lastIndex);
|
||||||
|
m_playlist.append(url);
|
||||||
|
endInsertRows();
|
||||||
|
return createIndex(lastIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PlaylistModel::removeAt(int index)
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= rowCount()) return false;
|
||||||
|
beginRemoveRows(QModelIndex(), index, index);
|
||||||
|
m_playlist.removeAt(index);
|
||||||
|
endRemoveRows();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PlaylistModel::indexOf(const QUrl &url) const
|
||||||
|
{
|
||||||
|
return m_playlist.indexOf(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList PlaylistModel::autoLoadFilterSuffixes() const
|
||||||
|
{
|
||||||
|
return m_autoLoadSuffixes;
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex PlaylistModel::createIndex(int row) const
|
||||||
|
{
|
||||||
|
return QAbstractItemModel::createIndex(row, 0, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
int PlaylistModel::rowCount(const QModelIndex &parent) const
|
||||||
|
{
|
||||||
|
return m_playlist.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant PlaylistModel::data(const QModelIndex &index, int role) const
|
||||||
|
{
|
||||||
|
if (!index.isValid()) return QVariant();
|
||||||
|
|
||||||
|
switch (role) {
|
||||||
|
case Qt::DisplayRole:
|
||||||
|
return m_playlist.at(index.row()).fileName();
|
||||||
|
case UrlRole:
|
||||||
|
return m_playlist.at(index.row());
|
||||||
|
}
|
||||||
|
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
PlaylistManager::PlaylistManager(QObject *parent)
|
||||||
|
: QObject(parent)
|
||||||
|
{
|
||||||
|
connect(&m_model, &PlaylistModel::rowsRemoved, this,
|
||||||
|
[this](const QModelIndex &, int, int) {
|
||||||
|
if (m_model.rowCount() <= m_currentIndex) {
|
||||||
|
setProperty("currentIndex", m_currentIndex - 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
auto onRowCountChanged = [this](){
|
||||||
|
emit totalCountChanged(m_model.rowCount());
|
||||||
|
};
|
||||||
|
|
||||||
|
connect(&m_model, &PlaylistModel::rowsInserted, this, onRowCountChanged);
|
||||||
|
connect(&m_model, &PlaylistModel::rowsRemoved, this, onRowCountChanged);
|
||||||
|
connect(&m_model, &PlaylistModel::modelReset, this, onRowCountChanged);
|
||||||
|
}
|
||||||
|
|
||||||
PlaylistManager::~PlaylistManager()
|
PlaylistManager::~PlaylistManager()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlaylistManager::setPlaylistType(PlaylistManager::PlaylistType type)
|
const PlaylistModel *PlaylistManager::model() const
|
||||||
{
|
{
|
||||||
m_type = type;
|
return &m_model;
|
||||||
}
|
|
||||||
|
|
||||||
PlaylistManager::PlaylistType PlaylistManager::playlistType() const
|
|
||||||
{
|
|
||||||
return m_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList PlaylistManager::autoLoadFilterSuffix() const
|
|
||||||
{
|
|
||||||
return m_autoLoadSuffix;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlaylistManager::setAutoLoadFilterSuffix(const QStringList & nameFilters)
|
|
||||||
{
|
|
||||||
m_autoLoadSuffix = nameFilters;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PlaylistManager::clear()
|
|
||||||
{
|
|
||||||
m_currentIndex = -1;
|
|
||||||
m_playlist.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlaylistManager::setPlaylist(const QList<QUrl> &urls)
|
void PlaylistManager::setPlaylist(const QList<QUrl> &urls)
|
||||||
{
|
{
|
||||||
m_playlist = urls;
|
m_model.setPlaylist(urls);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlaylistManager::setCurrentFile(const QString & filePath)
|
QModelIndex PlaylistManager::loadPlaylist(const QList<QUrl> &urls)
|
||||||
{
|
{
|
||||||
QFileInfo info(filePath);
|
QModelIndex idx = m_model.loadPlaylist(urls);
|
||||||
QDir dir(info.path());
|
setProperty("currentIndex", idx.row());
|
||||||
QString && currentFileName = info.fileName();
|
return idx;
|
||||||
|
|
||||||
switch (playlistType()) {
|
|
||||||
case PL_SAMEFOLDER: {
|
|
||||||
if (dir.path() == m_currentDir) {
|
|
||||||
int index = indexOf(filePath);
|
|
||||||
m_currentIndex = index == -1 ? appendFile(filePath) : index;
|
|
||||||
} else {
|
|
||||||
QStringList entryList = dir.entryList(
|
|
||||||
m_autoLoadSuffix,
|
|
||||||
QDir::Files | QDir::NoSymLinks, QDir::NoSort);
|
|
||||||
|
|
||||||
QCollator collator;
|
|
||||||
collator.setNumericMode(true);
|
|
||||||
|
|
||||||
std::sort(entryList.begin(), entryList.end(), collator);
|
|
||||||
|
|
||||||
clear();
|
|
||||||
|
|
||||||
int index = -1;
|
|
||||||
for (int i = 0; i < entryList.count(); i++) {
|
|
||||||
const QString & fileName = entryList.at(i);
|
|
||||||
const QString & oneEntry = dir.absoluteFilePath(fileName);
|
|
||||||
const QUrl & url = QUrl::fromLocalFile(oneEntry);
|
|
||||||
m_playlist.append(url);
|
|
||||||
if (fileName == currentFileName) {
|
|
||||||
index = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_currentIndex = index == -1 ? appendFile(filePath) : index;
|
|
||||||
m_currentDir = dir.path();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PL_USERPLAYLIST:{
|
|
||||||
int index = indexOf(filePath);
|
|
||||||
m_currentIndex = index == -1 ? appendFile(filePath) : index;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
emit currentIndexChanged(m_currentIndex);
|
|
||||||
emit loaded(m_playlist.count());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlaylistManager::setCurrentIndex(int index)
|
int PlaylistManager::totalCount() const
|
||||||
{
|
{
|
||||||
if (index < 0 || index >= m_playlist.count()) return;
|
return m_model.rowCount();
|
||||||
m_currentIndex = index;
|
|
||||||
emit currentIndexChanged(m_currentIndex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int PlaylistManager::appendFile(const QString &filePath)
|
QModelIndex PlaylistManager::previousIndex() const
|
||||||
{
|
{
|
||||||
int index = m_playlist.length();
|
int count = totalCount();
|
||||||
m_playlist.append(QUrl::fromLocalFile(filePath));
|
if (count == 0) return QModelIndex();
|
||||||
|
|
||||||
return index;
|
return m_model.createIndex(m_currentIndex - 1 < 0 ? count - 1 : m_currentIndex - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: this will only remove file out of the list, this will NOT delete the file
|
QModelIndex PlaylistManager::nextIndex() const
|
||||||
void PlaylistManager::removeFileAt(int index)
|
|
||||||
{
|
{
|
||||||
m_playlist.removeAt(index);
|
int count = totalCount();
|
||||||
|
if (count == 0) return QModelIndex();
|
||||||
|
|
||||||
if (m_playlist.count() <= m_currentIndex) {
|
return m_model.createIndex(m_currentIndex + 1 == count ? 0 : m_currentIndex + 1);
|
||||||
m_currentIndex--;
|
}
|
||||||
|
|
||||||
|
QModelIndex PlaylistManager::curIndex() const
|
||||||
|
{
|
||||||
|
return m_model.createIndex(m_currentIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlaylistManager::setCurrentIndex(const QModelIndex &index)
|
||||||
|
{
|
||||||
|
if (index.isValid() && index.row() >= 0 && index.row() < totalCount()) {
|
||||||
|
setProperty("currentIndex", index.row());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int PlaylistManager::indexOf(const QString &filePath)
|
QUrl PlaylistManager::urlByIndex(const QModelIndex &index)
|
||||||
{
|
{
|
||||||
const QUrl & url = QUrl::fromLocalFile(filePath);
|
return m_model.data(index, PlaylistModel::UrlRole).toUrl();
|
||||||
return m_playlist.indexOf(url);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int PlaylistManager::count() const
|
QString PlaylistManager::localFileByIndex(const QModelIndex &index)
|
||||||
{
|
{
|
||||||
return m_playlist.count();
|
return urlByIndex(index).toLocalFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<int, QString> PlaylistManager::previousFile() const
|
bool PlaylistManager::removeAt(const QModelIndex &index)
|
||||||
{
|
{
|
||||||
int count = m_playlist.count();
|
return m_model.removeAt(index.row());
|
||||||
if (count == 0) return std::make_tuple(-1, QString());
|
|
||||||
|
|
||||||
int index = m_currentIndex - 1 < 0 ? count - 1 : m_currentIndex - 1;
|
|
||||||
return std::make_tuple(index, m_playlist.at(index).toLocalFile());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<int, QString> PlaylistManager::nextFile() const
|
void PlaylistManager::setAutoLoadFilterSuffixes(const QStringList &nameFilters)
|
||||||
{
|
{
|
||||||
int count = m_playlist.count();
|
m_model.setProperty("autoLoadFilterSuffixes", nameFilters);
|
||||||
if (count == 0) return std::make_tuple(-1, QString());
|
|
||||||
|
|
||||||
int index = m_currentIndex + 1 == count ? 0 : m_currentIndex + 1;
|
|
||||||
return std::make_tuple(index, m_playlist.at(index).toLocalFile());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::tuple<int, QString> PlaylistManager::currentFile() const
|
|
||||||
{
|
|
||||||
if (m_playlist.count() == 0) return std::make_tuple(-1, QString());
|
|
||||||
|
|
||||||
return std::make_tuple(m_currentIndex, m_playlist.at(m_currentIndex).toLocalFile());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::tuple<int, QUrl> PlaylistManager::currentFileUrl() const
|
|
||||||
{
|
|
||||||
if (m_playlist.count() == 0) return std::make_tuple(-1, QUrl());
|
|
||||||
|
|
||||||
return std::make_tuple(m_currentIndex, m_playlist.at(m_currentIndex));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QUrl> PlaylistManager::convertToUrlList(const QStringList &files)
|
QList<QUrl> PlaylistManager::convertToUrlList(const QStringList &files)
|
||||||
|
@ -1,10 +1,47 @@
|
|||||||
// SPDX-FileCopyrightText: 2022 Gary Wang <wzc782970009@gmail.com>
|
// SPDX-FileCopyrightText: 2024 Gary Wang <git@blumia.net>
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QObject>
|
#include <QAbstractListModel>
|
||||||
|
|
||||||
|
class PlaylistModel : public QAbstractListModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
enum PlaylistRole {
|
||||||
|
UrlRole = Qt::UserRole
|
||||||
|
};
|
||||||
|
Q_ENUM(PlaylistRole)
|
||||||
|
Q_PROPERTY(QStringList autoLoadFilterSuffixes MEMBER m_autoLoadSuffixes NOTIFY autoLoadFilterSuffixesChanged)
|
||||||
|
|
||||||
|
explicit PlaylistModel(QObject *parent = nullptr);
|
||||||
|
~PlaylistModel();
|
||||||
|
|
||||||
|
void setPlaylist(const QList<QUrl> & urls);
|
||||||
|
QModelIndex loadPlaylist(const QList<QUrl> & urls);
|
||||||
|
QModelIndex loadPlaylist(const QUrl & url);
|
||||||
|
QModelIndex appendToPlaylist(const QUrl & url);
|
||||||
|
bool removeAt(int index);
|
||||||
|
int indexOf(const QUrl & url) const;
|
||||||
|
QStringList autoLoadFilterSuffixes() const;
|
||||||
|
|
||||||
|
QModelIndex createIndex(int row) const;
|
||||||
|
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||||
|
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void autoLoadFilterSuffixesChanged(QStringList suffixes);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// model data
|
||||||
|
QList<QUrl> m_playlist;
|
||||||
|
// properties
|
||||||
|
QStringList m_autoLoadSuffixes = {};
|
||||||
|
// internal
|
||||||
|
QString m_currentDir;
|
||||||
|
};
|
||||||
|
|
||||||
class PlaylistManager : public QObject
|
class PlaylistManager : public QObject
|
||||||
{
|
{
|
||||||
@ -12,47 +49,32 @@ class PlaylistManager : public QObject
|
|||||||
public:
|
public:
|
||||||
Q_PROPERTY(int currentIndex MEMBER m_currentIndex NOTIFY currentIndexChanged)
|
Q_PROPERTY(int currentIndex MEMBER m_currentIndex NOTIFY currentIndexChanged)
|
||||||
|
|
||||||
enum PlaylistType {
|
explicit PlaylistManager(QObject *parent = nullptr);
|
||||||
PL_USERPLAYLIST, // Regular playlist, managed by user.
|
|
||||||
PL_SAMEFOLDER // PlaylistManager managed playlist, loaded from files from same folder.
|
|
||||||
};
|
|
||||||
|
|
||||||
explicit PlaylistManager(PlaylistType type = PL_USERPLAYLIST, QObject *parent = nullptr);
|
|
||||||
~PlaylistManager();
|
~PlaylistManager();
|
||||||
|
|
||||||
void setPlaylistType(PlaylistType type);
|
const PlaylistModel * model() const;
|
||||||
PlaylistType playlistType() const;
|
|
||||||
|
|
||||||
QStringList autoLoadFilterSuffix() const;
|
void setPlaylist(const QList<QUrl> & url);
|
||||||
void setAutoLoadFilterSuffix(const QStringList &nameFilters);
|
QModelIndex loadPlaylist(const QList<QUrl> & urls);
|
||||||
|
|
||||||
void clear();
|
int totalCount() const;
|
||||||
|
QModelIndex previousIndex() const;
|
||||||
|
QModelIndex nextIndex() const;
|
||||||
|
QModelIndex curIndex() const;
|
||||||
|
void setCurrentIndex(const QModelIndex & index);
|
||||||
|
QUrl urlByIndex(const QModelIndex & index);
|
||||||
|
QString localFileByIndex(const QModelIndex & index);
|
||||||
|
bool removeAt(const QModelIndex & index);
|
||||||
|
|
||||||
void setPlaylist(const QList<QUrl> & urls);
|
void setAutoLoadFilterSuffixes(const QStringList &nameFilters);
|
||||||
void setCurrentFile(const QString & filePath);
|
|
||||||
void setCurrentIndex(int index);
|
|
||||||
int appendFile(const QString & filePath);
|
|
||||||
void removeFileAt(int index);
|
|
||||||
int indexOf(const QString & filePath);
|
|
||||||
|
|
||||||
int count() const;
|
|
||||||
|
|
||||||
std::tuple<int, QString> previousFile() const;
|
|
||||||
std::tuple<int, QString> nextFile() const;
|
|
||||||
std::tuple<int, QString> currentFile() const;
|
|
||||||
std::tuple<int, QUrl> currentFileUrl() const;
|
|
||||||
|
|
||||||
static QList<QUrl> convertToUrlList(const QStringList & files);
|
static QList<QUrl> convertToUrlList(const QStringList & files);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void loaded(int length);
|
|
||||||
void currentIndexChanged(int index);
|
void currentIndexChanged(int index);
|
||||||
|
void totalCountChanged(int count);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QList<QUrl> m_playlist;
|
int m_currentIndex;
|
||||||
PlaylistType m_type;
|
PlaylistModel m_model;
|
||||||
QString m_currentDir;
|
|
||||||
int m_currentIndex = -1;
|
|
||||||
QStringList m_autoLoadSuffix = {};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user