refactor: use extensible design for fetching playlist from single file
This commit is contained in:
+6
-2
@@ -53,7 +53,9 @@ set (PPIC_CPP_FILES
|
|||||||
app/exiv2wrapper.cpp
|
app/exiv2wrapper.cpp
|
||||||
app/playlistmanager.cpp
|
app/playlistmanager.cpp
|
||||||
app/fileopeneventhandler.cpp
|
app/fileopeneventhandler.cpp
|
||||||
app/winplaylistpatch.cpp
|
app/playlistscout.cpp
|
||||||
|
app/playlistscouts/qtscout.cpp
|
||||||
|
app/playlistscouts/explorerscout.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set (PPIC_HEADER_FILES
|
set (PPIC_HEADER_FILES
|
||||||
@@ -71,7 +73,9 @@ set (PPIC_HEADER_FILES
|
|||||||
app/exiv2wrapper.h
|
app/exiv2wrapper.h
|
||||||
app/playlistmanager.h
|
app/playlistmanager.h
|
||||||
app/fileopeneventhandler.h
|
app/fileopeneventhandler.h
|
||||||
app/winplaylistpatch.h
|
app/playlistscout.h
|
||||||
|
app/playlistscouts/qtscout.h
|
||||||
|
app/playlistscouts/explorerscout.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set (PPIC_UI_FILES
|
set (PPIC_UI_FILES
|
||||||
|
|||||||
+7
-43
@@ -3,7 +3,7 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
#include "playlistmanager.h"
|
#include "playlistmanager.h"
|
||||||
#include "winplaylistpatch.h"
|
#include "playlistscout.h"
|
||||||
|
|
||||||
#include <QCollator>
|
#include <QCollator>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
@@ -72,50 +72,14 @@ bool PlaylistManager::loadSingleFilePlaylist(const QUrl& url) {
|
|||||||
if (!checkUrl(url))
|
if (!checkUrl(url))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
QList<QUrl> playlist;
|
// Scout playlist by given file
|
||||||
std::optional<qsizetype> idx = std::nullopt;
|
auto scoutResult = PlaylistScout::scout(url, m_allowedSuffixes);
|
||||||
|
if (!scoutResult.has_value()) {
|
||||||
#ifdef Q_OS_WIN
|
return false;
|
||||||
// In Windows, Qt approach can not aware Windows Explorer custom sort order.
|
|
||||||
// So we need to try using Win32 functions for fetching it at first
|
|
||||||
if (!WinPlaylistPatch::loadSingleFilePlaylist(url, m_allowedSuffixes, playlist, idx)) {
|
|
||||||
#endif // Q_OS_WIN
|
|
||||||
|
|
||||||
// If Windows approach is failed or we are not in Windows,
|
|
||||||
// use Qt way to process it.
|
|
||||||
|
|
||||||
QFileInfo info(url.toLocalFile());
|
|
||||||
QDir dir(info.path());
|
|
||||||
QString currentFileName = info.fileName();
|
|
||||||
|
|
||||||
QStringList entryList = dir.entryList(
|
|
||||||
m_allowedSuffixes, QDir::Files | QDir::NoSymLinks, QDir::NoSort);
|
|
||||||
|
|
||||||
QCollator collator;
|
|
||||||
collator.setNumericMode(true);
|
|
||||||
|
|
||||||
std::sort(entryList.begin(), entryList.end(), collator);
|
|
||||||
|
|
||||||
playlist.clear();
|
|
||||||
idx = std::nullopt;
|
|
||||||
for (qsizetype i = 0; i < entryList.count(); i++) {
|
|
||||||
const QString &fileName = entryList.at(i);
|
|
||||||
const QString &oneEntry = dir.absoluteFilePath(fileName);
|
|
||||||
const QUrl &url = QUrl::fromLocalFile(oneEntry);
|
|
||||||
if (!checkUrl(url)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
playlist.append(url);
|
|
||||||
if (fileName == currentFileName) {
|
|
||||||
idx = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
}
|
}
|
||||||
#endif // Q_OS_WIN
|
|
||||||
|
|
||||||
setPlaylist(std::move(playlist), idx);
|
// Setup playlist with index
|
||||||
|
setPlaylist(std::move(scoutResult->playlist), scoutResult->indexHint);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2026 yyc12345 <yyc12321@outlook.com>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#include "playlistscout.h"
|
||||||
|
|
||||||
|
#include "playlistscouts/qtscout.h"
|
||||||
|
#include "playlistscouts/explorerscout.h"
|
||||||
|
|
||||||
|
std::optional<PlaylistScout::ScoutResult> PlaylistScout::scout(
|
||||||
|
const QUrl &url, const QStringList &allowedSuffixes) {
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
// In Windows, Qt approach can not aware Windows Explorer custom sort order.
|
||||||
|
// So we need to try using Win32 functions for fetching it at first.
|
||||||
|
if (auto rv = PlaylistScout::Explorer::scout(url, allowedSuffixes); rv.has_value()) {
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
#endif // Q_OS_WIN
|
||||||
|
|
||||||
|
// TODO: We may add macOS Finder, KDE Dolphin and etc supports in future.
|
||||||
|
|
||||||
|
// Qt way is the last fallback.
|
||||||
|
return PlaylistScout::Qt::scout(url, allowedSuffixes);
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2026 yyc12345 <yyc12321@outlook.com>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QUrl>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QList>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
namespace PlaylistScout {
|
||||||
|
/// The result of scout
|
||||||
|
struct ScoutResult {
|
||||||
|
/// The final fetched playlist (it can be empty).
|
||||||
|
/// Each item must be a QUrl pointing to a local file.
|
||||||
|
QList<QUrl> playlist;
|
||||||
|
/// The index of given file located in playlist.
|
||||||
|
/// Nullopt if it is not presented in playlist.
|
||||||
|
std::optional<qsizetype> indexHint;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @brief Scout available image files in given file's parent dir with given allowed suffixes.
|
||||||
|
/// @param[in] url The path to file whose parent dir is our target dir for finding image files.
|
||||||
|
/// @param[in] allowedSuffixes
|
||||||
|
/// Each items in this list is a wildcard pattern for matching allowed file name, like \c *.png .
|
||||||
|
/// The fetched item will be preserved if its name matching any of them.
|
||||||
|
/// If this list is empty, there is no restrictions for finding files.
|
||||||
|
/// @return Scout result if success, otherwise nullopt.
|
||||||
|
std::optional<ScoutResult> scout(const QUrl &url, const QStringList &allowedSuffixes);
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
//
|
//
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
#include "winplaylistpatch.h"
|
#include "explorerscout.h"
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
|
|
||||||
@@ -242,9 +242,9 @@ static ComPtr<IFolderView2> FindLiveFolderView(const QString& targetFolderPath)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WinPlaylistPatch::loadSingleFilePlaylist(
|
std::optional<PlaylistScout::ScoutResult> PlaylistScout::Explorer::scout(
|
||||||
const QUrl &url, const QStringList &allowedSuffixes, QList<QUrl> &playlist,
|
const QUrl &url, const QStringList &allowedSuffixes) {
|
||||||
std::optional<qsizetype> &indexHint) {
|
PlaylistScout::ScoutResult rv;
|
||||||
|
|
||||||
QFileInfo info(url.toLocalFile());
|
QFileInfo info(url.toLocalFile());
|
||||||
QString folderPath = info.path();
|
QString folderPath = info.path();
|
||||||
@@ -263,14 +263,14 @@ bool WinPlaylistPatch::loadSingleFilePlaylist(
|
|||||||
ComGuard comGuard;
|
ComGuard comGuard;
|
||||||
if (!comGuard.IsInitialized()) {
|
if (!comGuard.IsInitialized()) {
|
||||||
ReportError("COM initialization failed");
|
ReportError("COM initialization failed");
|
||||||
return false;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find a live Explorer window that is currently displaying the target folder.
|
// Find a live Explorer window that is currently displaying the target folder.
|
||||||
ComPtr<IFolderView2> folderView2 = FindLiveFolderView(folderPath);
|
ComPtr<IFolderView2> folderView2 = FindLiveFolderView(folderPath);
|
||||||
if (!folderView2) {
|
if (!folderView2) {
|
||||||
ReportError("No open Explorer window matches the folder: " + folderPath);
|
ReportError("No open Explorer window matches the folder: " + folderPath);
|
||||||
return false;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get items already sorted in Explorer's view order, as an IShellItemArray.
|
// Get items already sorted in Explorer's view order, as an IShellItemArray.
|
||||||
@@ -279,7 +279,7 @@ bool WinPlaylistPatch::loadSingleFilePlaylist(
|
|||||||
if (FAILED(folderView2->Items(SVGIO_ALLVIEW | SVGIO_FLAG_VIEWORDER,
|
if (FAILED(folderView2->Items(SVGIO_ALLVIEW | SVGIO_FLAG_VIEWORDER,
|
||||||
IID_PPV_ARGS(itemArray.GetAddressOf())))) {
|
IID_PPV_ARGS(itemArray.GetAddressOf())))) {
|
||||||
ReportError("IFolderView2::Items(SVGIO_ALLVIEW | SVGIO_FLAG_VIEWORDER) failed");
|
ReportError("IFolderView2::Items(SVGIO_ALLVIEW | SVGIO_FLAG_VIEWORDER) failed");
|
||||||
return false;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD itemCount = 0;
|
DWORD itemCount = 0;
|
||||||
@@ -320,13 +320,13 @@ bool WinPlaylistPatch::loadSingleFilePlaylist(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
playlist.append(QUrl::fromLocalFile(filePath));
|
rv.playlist.append(QUrl::fromLocalFile(filePath));
|
||||||
if (fileName == currentFileName) {
|
if (fileName == currentFileName) {
|
||||||
indexHint = playlist.size() - 1;
|
rv.indexHint = rv.playlist.size() - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // Q_OS_WIN
|
#endif // Q_OS_WIN
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2026 yyc12345 <yyc12321@outlook.com>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../playlistscout.h"
|
||||||
|
#include <QtSystemDetection>
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
|
||||||
|
namespace PlaylistScout::Explorer {
|
||||||
|
std::optional<ScoutResult> scout(const QUrl &url, const QStringList &allowedSuffixes);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // Q_OS_WIN
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2025 Gary Wang <git@blumia.net>
|
||||||
|
// SPDX-FileCopyrightText: 2026 yyc12345 <yyc12321@outlook.com>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#include "qtscout.h"
|
||||||
|
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QCollator>
|
||||||
|
|
||||||
|
std::optional<PlaylistScout::ScoutResult> PlaylistScout::Qt::scout(
|
||||||
|
const QUrl &url, const QStringList &allowedSuffixes) {
|
||||||
|
PlaylistScout::ScoutResult rv;
|
||||||
|
|
||||||
|
QFileInfo info(url.toLocalFile());
|
||||||
|
QDir dir(info.path());
|
||||||
|
QString currentFileName = info.fileName();
|
||||||
|
|
||||||
|
QStringList entryList = dir.entryList(
|
||||||
|
allowedSuffixes, QDir::Files | QDir::NoSymLinks, QDir::NoSort);
|
||||||
|
|
||||||
|
QCollator collator;
|
||||||
|
collator.setNumericMode(true);
|
||||||
|
|
||||||
|
std::sort(entryList.begin(), entryList.end(), collator);
|
||||||
|
|
||||||
|
for (qsizetype i = 0; i < entryList.count(); i++) {
|
||||||
|
const QString &fileName = entryList.at(i);
|
||||||
|
const QString &oneEntry = dir.absoluteFilePath(fileName);
|
||||||
|
const QUrl &url = QUrl::fromLocalFile(oneEntry);
|
||||||
|
|
||||||
|
rv.playlist.append(url);
|
||||||
|
if (fileName == currentFileName) {
|
||||||
|
rv.indexHint = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2026 yyc12345 <yyc12321@outlook.com>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../playlistscout.h"
|
||||||
|
|
||||||
|
namespace PlaylistScout::Qt {
|
||||||
|
std::optional<ScoutResult> scout(const QUrl &url, const QStringList &allowedSuffixes);
|
||||||
|
}
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: 2026 yyc12345 <yyc12321@outlook.com>
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: MIT
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QtSystemDetection>
|
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
|
|
||||||
#include <QUrl>
|
|
||||||
class WinPlaylistPatch
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static bool loadSingleFilePlaylist(const QUrl &url,
|
|
||||||
const QStringList &allowedSuffixes,
|
|
||||||
QList<QUrl> &playlist,
|
|
||||||
std::optional<qsizetype> &indexHint);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // Q_OS_WIN
|
|
||||||
Reference in New Issue
Block a user