Merge pull request #7159 from bparker06/qt_filterarchives

Qt: add option to filter extensions inside archives when adding to a playlist
This commit is contained in:
Twinaphex 2018-08-31 17:50:59 +02:00 committed by GitHub
commit b86164cccb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 185 additions and 11 deletions

View File

@ -3728,6 +3728,12 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_CORE,
"コア:")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_DATABASE,
"データベース:")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_EXTENSIONS,
"拡張子:")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_EXTENSIONS_PLACEHOLDER,
"(スペースで区切る。 既定は全部の拡張子)")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_FILTER_INSIDE_ARCHIVES,
"アーカイブの中に絞り込み")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_FOR_THUMBNAILS,
"(サムネイルを見つかることに使う)")
MSG_HASH(MENU_ENUM_LABEL_VALUE_QT_CONFIRM_DELETE_PLAYLIST_ITEM,

View File

@ -7266,6 +7266,18 @@ MSG_HASH(
MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_DATABASE,
"Database:"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_EXTENSIONS,
"Extensions:"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_EXTENSIONS_PLACEHOLDER,
"(space-separated; includes all by default)"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_FILTER_INSIDE_ARCHIVES,
"Filter inside archives"
)
MSG_HASH(
MENU_ENUM_LABEL_VALUE_QT_FOR_THUMBNAILS,
"(used to find thumbnails)"

View File

@ -1971,6 +1971,9 @@ enum msg_hash_enums
MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_PATH,
MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_CORE,
MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_DATABASE,
MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_EXTENSIONS,
MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_EXTENSIONS_PLACEHOLDER,
MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_FILTER_INSIDE_ARCHIVES,
MENU_ENUM_LABEL_VALUE_QT_FOR_THUMBNAILS,
MENU_ENUM_LABEL_VALUE_QT_CANNOT_ADD_TO_ALL_PLAYLISTS,
MENU_ENUM_LABEL_VALUE_QT_DELETE,

View File

@ -91,6 +91,9 @@ void MainWindow::onFileDropWidgetContextMenuRequested(const QPoint &pos)
QPoint cursorPos = QCursor::pos();
QHash<QString, QString> contentHash = getCurrentContentHash();
if (m_browserAndPlaylistTabWidget->tabText(m_browserAndPlaylistTabWidget->currentIndex()) != msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_TAB_PLAYLISTS))
return;
menu.reset(new QMenu(this));
downloadThumbnailAction.reset(new QAction(QString(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_DOWNLOAD_THUMBNAIL)), this));

View File

@ -8,6 +8,7 @@
#include <QInputDialog>
#include <QLayout>
#include <QScreen>
#include <QRegularExpression>
#include "../ui_qt.h"
#include "flowlayout.h"
@ -38,29 +39,86 @@ inline static bool comp_hash_label_key_lower(const QHash<QString, QString> &lhs,
}
/* https://stackoverflow.com/questions/7246622/how-to-create-a-slider-with-a-non-linear-scale */
static void addDirectoryFilesToList(QStringList &list, QDir &dir)
bool MainWindow::addDirectoryFilesToList(QProgressDialog *dialog, QStringList &list, QDir &dir, QStringList &extensions)
{
PlaylistEntryDialog *playlistDialog = playlistEntryDialog();
QStringList dirList = dir.entryList(QStringList(), QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System, QDir::Name);
int i;
for (i = 0; i < dirList.count(); i++)
{
QString path(dir.path() + "/" + dirList.at(i));
QByteArray pathArray = path.toUtf8();
QFileInfo fileInfo(path);
const char *pathData = pathArray.constData();
if (dialog->wasCanceled())
return false;
if (i % 25 == 0)
{
/* Needed to update progress dialog while doing a lot of stuff on the main thread. */
qApp->processEvents();
}
if (fileInfo.isDir())
{
QDir fileInfoDir(path);
bool success = addDirectoryFilesToList(dialog, list, fileInfoDir, extensions);
if (!success)
return false;
addDirectoryFilesToList(list, fileInfoDir);
continue;
}
if (fileInfo.isFile())
{
list.append(fileInfo.absoluteFilePath());
bool add = false;
if (extensions.isEmpty())
add = true;
else
{
if (extensions.contains(fileInfo.suffix()))
add = true;
else
{
if (path_is_compressed_file(pathData))
{
struct string_list *list = file_archive_get_file_list(pathData, NULL);
if (list)
{
if (list->size == 1)
{
/* Assume archives with one file should have that file loaded directly.
* Don't just extend this to add all files in a zip, because we might hit
* something like MAME/FBA where only the archives themselves are valid content. */
pathArray = (QString(pathData) + "#" + list->elems[0].data).toUtf8();
pathData = pathArray.constData();
if (!extensions.isEmpty() && playlistDialog->filterInArchive())
{
/* If the user chose to filter extensions inside archives, and this particular file inside the archive
* doesn't have one of the chosen extensions, then we skip it. */
if (extensions.contains(QFileInfo(pathData).suffix()))
add = true;
}
}
string_list_free(list);
}
}
}
}
if (add)
list.append(fileInfo.absoluteFilePath());
}
}
return true;
}
void MainWindow::onPlaylistFilesDropped(QStringList files)
@ -82,6 +140,7 @@ void MainWindow::addFilesToPlaylist(QStringList files)
QString selectedDatabase;
QString selectedName;
QString selectedPath;
QStringList selectedExtensions;
const char *currentPlaylistData = NULL;
playlist_t *playlist = NULL;
int i;
@ -130,6 +189,10 @@ void MainWindow::addFilesToPlaylist(QStringList files)
selectedPath = m_playlistEntryDialog->getSelectedPath();
selectedCore = m_playlistEntryDialog->getSelectedCore();
selectedDatabase = m_playlistEntryDialog->getSelectedDatabase();
selectedExtensions = m_playlistEntryDialog->getSelectedExtensions();
if (!selectedExtensions.isEmpty())
selectedExtensions.replaceInStrings(QRegularExpression("^\\."), "");
if (selectedDatabase.isEmpty())
selectedDatabase = QFileInfo(currentPlaylistPath).fileName();
@ -138,6 +201,9 @@ void MainWindow::addFilesToPlaylist(QStringList files)
dialog.reset(new QProgressDialog(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_GATHERING_LIST_OF_FILES), "Cancel", 0, 0, this));
dialog->setWindowModality(Qt::ApplicationModal);
dialog->show();
qApp->processEvents();
if (selectedName.isEmpty() || selectedPath.isEmpty() ||
selectedDatabase.isEmpty())
@ -166,12 +232,37 @@ void MainWindow::addFilesToPlaylist(QStringList files)
if (fileInfo.isDir())
{
QDir dir(path);
addDirectoryFilesToList(list, dir);
bool success = addDirectoryFilesToList(dialog.data(), list, dir, selectedExtensions);
if (!success)
return;
continue;
}
if (fileInfo.isFile())
list.append(fileInfo.absoluteFilePath());
{
bool add = false;
if (selectedExtensions.isEmpty())
add = true;
else
{
QByteArray pathArray = path.toUtf8();
const char *pathData = pathArray.constData();
if (selectedExtensions.contains(fileInfo.suffix()))
add = true;
else if (playlistDialog->filterInArchive() && path_is_compressed_file(pathData))
{
/* We'll add it here but really just delay the check until later when the archive contents are iterated. */
add = true;
}
}
if (add)
list.append(fileInfo.absoluteFilePath());
}
else if (files.count() == 1)
{
/* If adding a single file, tell user that it doesn't exist. */
@ -202,6 +293,7 @@ void MainWindow::addFilesToPlaylist(QStringList files)
if (dialog->wasCanceled())
{
/* Cancel out of everything, the current progress will not be written to the playlist at all. */
playlist_free(playlist);
return;
}
@ -209,13 +301,19 @@ void MainWindow::addFilesToPlaylist(QStringList files)
if (fileName.isEmpty())
continue;
/* a modal QProgressDialog calls processEvents() automatically in setValue() */
dialog->setValue(i + 1);
fileInfo = fileName;
if (files.count() == 1 && list.count() == 1 && i == 0)
/* Make sure we're looking at a user-specified field and not just "<multiple>"
* in case it was a folder with one file in it */
if (files.count() == 1 && list.count() == 1 && i == 0 && playlistDialog->nameFieldEnabled())
{
fileBaseNameArray = selectedName.toUtf8();
pathArray = QDir::toNativeSeparators(selectedPath).toUtf8();
}
/* Otherwise just use the file name itself (minus extension) for the playlist entry title */
else
{
fileBaseNameArray = fileInfo.completeBaseName().toUtf8();
@ -224,9 +322,6 @@ void MainWindow::addFilesToPlaylist(QStringList files)
fileNameNoExten = fileBaseNameArray.constData();
/* a modal QProgressDialog calls processEvents() automatically in setValue() */
dialog->setValue(i + 1);
pathData = pathArray.constData();
if (selectedCore.isEmpty())
@ -253,9 +348,22 @@ void MainWindow::addFilesToPlaylist(QStringList files)
{
if (list->size == 1)
{
/* assume archives with one file should have that file loaded directly */
/* Assume archives with one file should have that file loaded directly.
* Don't just extend this to add all files in a zip, because we might hit
* something like MAME/FBA where only the archives themselves are valid content. */
pathArray = QDir::toNativeSeparators(QString(pathData) + "#" + list->elems[0].data).toUtf8();
pathData = pathArray.constData();
if (!selectedExtensions.isEmpty() && playlistDialog->filterInArchive())
{
/* If the user chose to filter extensions inside archives, and this particular file inside the archive
* doesn't have one of the chosen extensions, then we skip it. */
if (!selectedExtensions.contains(QFileInfo(pathData).suffix()))
{
string_list_free(list);
continue;
}
}
}
string_list_free(list);

View File

@ -1,5 +1,6 @@
#include <QSettings>
#include <QLineEdit>
#include <QCheckBox>
#include <QComboBox>
#include <QFormLayout>
#include <QDialogButtonBox>
@ -33,17 +34,20 @@ PlaylistEntryDialog::PlaylistEntryDialog(MainWindow *mainwindow, QWidget *parent
,m_settings(mainwindow->settings())
,m_nameLineEdit(new QLineEdit(this))
,m_pathLineEdit(new QLineEdit(this))
,m_extensionsLineEdit(new QLineEdit(this))
,m_coreComboBox(new QComboBox(this))
,m_databaseComboBox(new QComboBox(this))
,m_extensionArchiveCheckBox(new QCheckBox(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_FILTER_INSIDE_ARCHIVES), this))
{
QFormLayout *form = new QFormLayout();
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
QVBoxLayout *databaseVBoxLayout = new QVBoxLayout();
QHBoxLayout *pathHBoxLayout = new QHBoxLayout();
QHBoxLayout *extensionHBoxLayout = new QHBoxLayout();
QLabel *databaseLabel = new QLabel(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_FOR_THUMBNAILS), this);
QToolButton *pathPushButton = new QToolButton(this);
pathPushButton->setText("...");
pathPushButton->setText(QStringLiteral("..."));
pathHBoxLayout->addWidget(m_pathLineEdit);
pathHBoxLayout->addWidget(pathPushButton);
@ -51,6 +55,14 @@ PlaylistEntryDialog::PlaylistEntryDialog(MainWindow *mainwindow, QWidget *parent
databaseVBoxLayout->addWidget(m_databaseComboBox);
databaseVBoxLayout->addWidget(databaseLabel);
extensionHBoxLayout->addWidget(m_extensionsLineEdit);
extensionHBoxLayout->addWidget(m_extensionArchiveCheckBox);
m_extensionsLineEdit->setPlaceholderText(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_EXTENSIONS_PLACEHOLDER));
/* Ensure placeholder text is completely visible. */
m_extensionsLineEdit->setMinimumWidth(QFontMetrics(m_extensionsLineEdit->font()).boundingRect(m_extensionsLineEdit->placeholderText()).width() + m_extensionsLineEdit->frameSize().width());
setWindowTitle(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY));
form->setFormAlignment(Qt::AlignCenter);
@ -68,6 +80,7 @@ PlaylistEntryDialog::PlaylistEntryDialog(MainWindow *mainwindow, QWidget *parent
form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_PATH), pathHBoxLayout);
form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_CORE), m_coreComboBox);
form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_DATABASE), databaseVBoxLayout);
form->addRow(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QT_PLAYLIST_ENTRY_EXTENSIONS), extensionHBoxLayout);
qobject_cast<QVBoxLayout*>(layout())->addLayout(form);
layout()->addItem(new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding));
@ -76,6 +89,11 @@ PlaylistEntryDialog::PlaylistEntryDialog(MainWindow *mainwindow, QWidget *parent
connect(pathPushButton, SIGNAL(clicked()), this, SLOT(onPathClicked()));
}
bool PlaylistEntryDialog::filterInArchive()
{
return m_extensionArchiveCheckBox->isChecked();
}
void PlaylistEntryDialog::onPathClicked()
{
QString filePath = QFileDialog::getOpenFileName(this);
@ -164,6 +182,11 @@ void PlaylistEntryDialog::loadPlaylistOptions()
}
}
bool PlaylistEntryDialog::nameFieldEnabled()
{
return m_nameLineEdit->isEnabled();
}
void PlaylistEntryDialog::setEntryValues(const QHash<QString, QString> &contentHash)
{
QString db;
@ -233,6 +256,18 @@ const QString PlaylistEntryDialog::getSelectedDatabase()
return m_databaseComboBox->currentData(Qt::UserRole).toString();
}
const QStringList PlaylistEntryDialog::getSelectedExtensions()
{
QStringList list;
QString text = m_extensionsLineEdit->text();
/* Otherwise it would create a QStringList with a single blank entry... */
if (!text.isEmpty())
list = text.split(' ');
return list;
}
void PlaylistEntryDialog::onAccepted()
{
}

View File

@ -6,6 +6,7 @@
class QSettings;
class QLineEdit;
class QComboBox;
class QCheckBox;
class MainWindow;
class PlaylistEntryDialog : public QDialog
@ -17,6 +18,9 @@ public:
const QString getSelectedDatabase();
const QString getSelectedName();
const QString getSelectedPath();
const QStringList getSelectedExtensions();
bool filterInArchive();
bool nameFieldEnabled();
void setEntryValues(const QHash<QString, QString> &contentHash);
public slots:
bool showDialog(const QHash<QString, QString> &hash = QHash<QString, QString>());
@ -32,8 +36,10 @@ private:
QSettings *m_settings;
QLineEdit *m_nameLineEdit;
QLineEdit *m_pathLineEdit;
QLineEdit *m_extensionsLineEdit;
QComboBox *m_coreComboBox;
QComboBox *m_databaseComboBox;
QCheckBox *m_extensionArchiveCheckBox;
};
#endif

View File

@ -429,6 +429,7 @@ private:
bool updateCurrentPlaylistEntry(const QHash<QString, QString> &contentHash);
int extractArchive(QString path);
void removeUpdateTempFiles();
bool addDirectoryFilesToList(QProgressDialog *dialog, QStringList &list, QDir &dir, QStringList &extensions);
QVector<QHash<QString, QString> > getPlaylistItems(QString pathString);
LoadCoreWindow *m_loadCoreWindow;