From 68e62f737237483834d57187a955c79a665b8a8e Mon Sep 17 00:00:00 2001 From: ronso0 Date: Tue, 23 Nov 2021 00:16:31 +0100 Subject: [PATCH 1/3] add QFileDialog helper extensionFromFileFilter() --- src/util/string.h | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/util/string.h b/src/util/string.h index 64941f4c4bd5..8787263e3f96 100644 --- a/src/util/string.h +++ b/src/util/string.h @@ -2,7 +2,9 @@ #include #include +#include #include +#include #include #include @@ -37,3 +39,31 @@ inline QString coloredLinkString( QStringLiteral(";\" href=\"") + baseUrl + extUrl + QStringLiteral("\">") + text + QStringLiteral(""); } + +// Check if the extension from the file filter was added to the file base name. +// Otherwise add it manually. +// Works around https://bugreports.qt.io/browse/QTBUG-27186 +inline QString filePathWithSelectedExtension(const QString& fileLocationDlg, + const QString& fileFilter) { + if (fileLocationDlg.isEmpty()) { + return QString(); + } + QString fileLocation = fileLocationDlg; + if (fileFilter.isEmpty()) { + return fileLocation; + } + + // Extract 'ext' from QFileDialog display string 'Funky type (*.ext)' + QString ext; + const QRegularExpression extRgxp("(\\*\\.)(.*?)(\\))"); + QRegularExpressionMatch extMatch = extRgxp.match(fileFilter); + if (!extMatch.hasMatch()) { + return fileLocation; + } + ext = extMatch.captured(2); + QFileInfo fileName(fileLocation); + if (!ext.isEmpty() && fileName.suffix() != ext) { + fileLocation.append(".").append(ext); + } + return fileLocation; +} From 53749d2907ea29fb8d94b4335d16ef0ddc858039 Mon Sep 17 00:00:00 2001 From: ronso0 Date: Tue, 23 Nov 2021 01:12:40 +0100 Subject: [PATCH 2/3] playlist export: ensure selected extension is added... and change variables to lowerCamelCase --- src/library/baseplaylistfeature.cpp | 30 ++++++++++++++------------- src/library/crate/cratefeature.cpp | 32 ++++++++++++++++------------- 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/src/library/baseplaylistfeature.cpp b/src/library/baseplaylistfeature.cpp index f7e8d8fca040..2ae0170cd777 100644 --- a/src/library/baseplaylistfeature.cpp +++ b/src/library/baseplaylistfeature.cpp @@ -19,6 +19,7 @@ #include "moc_baseplaylistfeature.cpp" #include "track/track.h" #include "util/assert.h" +#include "util/string.h" #include "widget/wlibrary.h" #include "widget/wlibrarytextbrowser.h" @@ -461,19 +462,20 @@ void BasePlaylistFeature::slotExportPlaylist() { // Open a dialog to let the user choose the file location for playlist export. // The location is set to the last used directory for import/export and the file // name to the playlist name. - QString filefilter = tr("M3U Playlist (*.m3u)"); - QString file_location = QFileDialog::getSaveFileName( + QString fileFilter = tr("M3U Playlist (*.m3u)"); + QString fileLocationDlg = QFileDialog::getSaveFileName( nullptr, tr("Export Playlist"), lastPlaylistDirectory.append("/").append(playlistName), tr("M3U Playlist (*.m3u);;M3U8 Playlist (*.m3u8);;" "PLS Playlist (*.pls);;Text CSV (*.csv);;Readable Text (*.txt)"), - &filefilter); + &fileFilter); + QString fileLocation = filePathWithSelectedExtension(fileLocationDlg, fileFilter); // Exit method if user cancelled the open dialog. - if (file_location.isNull() || file_location.isEmpty()) { + if (fileLocation.isEmpty()) { return; } - QFileInfo fileName(file_location); + QFileInfo fileName(fileLocation); // Update the import/export playlist directory m_pConfig->set(ConfigKey("[Library]", "LastImportExportPlaylistDirectory"), ConfigValue(fileName.dir().absolutePath())); @@ -498,25 +500,25 @@ void BasePlaylistFeature::slotExportPlaylist() { bool useRelativePath = m_pConfig->getValue( ConfigKey("[Library]", "UseRelativePathOnExport")); - if (file_location.endsWith(".csv", Qt::CaseInsensitive)) { - ParserCsv::writeCSVFile(file_location, pPlaylistTableModel.data(), useRelativePath); - } else if (file_location.endsWith(".txt", Qt::CaseInsensitive)) { + if (fileLocation.endsWith(".csv", Qt::CaseInsensitive)) { + ParserCsv::writeCSVFile(fileLocation, pPlaylistTableModel.data(), useRelativePath); + } else if (fileLocation.endsWith(".txt", Qt::CaseInsensitive)) { if (m_playlistDao.getHiddenType(pPlaylistTableModel->getPlaylist()) == PlaylistDAO::PLHT_SET_LOG) { - ParserCsv::writeReadableTextFile(file_location, pPlaylistTableModel.data(), true); + ParserCsv::writeReadableTextFile(fileLocation, pPlaylistTableModel.data(), true); } else { - ParserCsv::writeReadableTextFile(file_location, pPlaylistTableModel.data(), false); + ParserCsv::writeReadableTextFile(fileLocation, pPlaylistTableModel.data(), false); } } else { // Create and populate a list of files of the playlist - QList playlist_items; + QList playlistItems; int rows = pPlaylistTableModel->rowCount(); for (int i = 0; i < rows; ++i) { QModelIndex index = pPlaylistTableModel->index(i, 0); - playlist_items << pPlaylistTableModel->getTrackLocation(index); + playlistItems << pPlaylistTableModel->getTrackLocation(index); } exportPlaylistItemsIntoFile( - file_location, - playlist_items, + fileLocation, + playlistItems, useRelativePath); } } diff --git a/src/library/crate/cratefeature.cpp b/src/library/crate/cratefeature.cpp index 2d0de89876b6..da2e9eefe2a0 100644 --- a/src/library/crate/cratefeature.cpp +++ b/src/library/crate/cratefeature.cpp @@ -22,6 +22,7 @@ #include "sources/soundsourceproxy.h" #include "track/track.h" #include "util/dnd.h" +#include "util/string.h" #include "widget/wlibrary.h" #include "widget/wlibrarysidebar.h" #include "widget/wlibrarytextbrowser.h" @@ -686,18 +687,21 @@ void CrateFeature::slotExportPlaylist() { ConfigKey("[Library]", "LastImportExportCrateDirectory"), QStandardPaths::writableLocation(QStandardPaths::MusicLocation)); - QString file_location = QFileDialog::getSaveFileName(nullptr, + QString fileFilter = tr("M3U Playlist (*.m3u)"); + QString fileLocationDlg = QFileDialog::getSaveFileName( + nullptr, tr("Export Crate"), lastCrateDirectory.append("/").append(crate.getName()), tr("M3U Playlist (*.m3u);;M3U8 Playlist (*.m3u8);;PLS Playlist " - "(*.pls);;Text CSV (*.csv);;Readable Text (*.txt)")); + "(*.pls);;Text CSV (*.csv);;Readable Text (*.txt)"), + &fileFilter); + QString fileLocation = filePathWithSelectedExtension(fileLocationDlg, fileFilter); // Exit method if user cancelled the open dialog. - if (file_location.isNull() || file_location.isEmpty()) { + if (fileLocation.isEmpty()) { return; } - + QFileInfo fileName(fileLocation); // Update the import/export crate directory - QFileInfo fileName(file_location); m_pConfig->set(ConfigKey("[Library]","LastImportExportCrateDirectory"), ConfigValue(fileName.dir().absolutePath())); @@ -718,21 +722,21 @@ void CrateFeature::slotExportPlaylist() { pCrateTableModel->selectCrate(m_crateTableModel.selectedCrate()); pCrateTableModel->select(); - if (file_location.endsWith(".csv", Qt::CaseInsensitive)) { - ParserCsv::writeCSVFile(file_location, pCrateTableModel.data(), useRelativePath); - } else if (file_location.endsWith(".txt", Qt::CaseInsensitive)) { - ParserCsv::writeReadableTextFile(file_location, pCrateTableModel.data(), false); - } else{ + if (fileLocation.endsWith(".csv", Qt::CaseInsensitive)) { + ParserCsv::writeCSVFile(fileLocation, pCrateTableModel.data(), useRelativePath); + } else if (fileLocation.endsWith(".txt", Qt::CaseInsensitive)) { + ParserCsv::writeReadableTextFile(fileLocation, pCrateTableModel.data(), false); + } else { // populate a list of files of the crate - QList playlist_items; + QList playlistItems; int rows = pCrateTableModel->rowCount(); for (int i = 0; i < rows; ++i) { QModelIndex index = m_crateTableModel.index(i, 0); - playlist_items << m_crateTableModel.getTrackLocation(index); + playlistItems << m_crateTableModel.getTrackLocation(index); } exportPlaylistItemsIntoFile( - file_location, - playlist_items, + fileLocation, + playlistItems, useRelativePath); } } From aa72e10c4bb7948415676d5881768f4ac63e49e4 Mon Sep 17 00:00:00 2001 From: ronso0 Date: Tue, 23 Nov 2021 01:52:44 +0100 Subject: [PATCH 3/3] playlist import/export: use const directory configkey --- src/library/baseplaylistfeature.cpp | 15 +++++++++++---- src/library/crate/cratefeature.cpp | 17 ++++++++++------- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/library/baseplaylistfeature.cpp b/src/library/baseplaylistfeature.cpp index 2ae0170cd777..486771d7fd89 100644 --- a/src/library/baseplaylistfeature.cpp +++ b/src/library/baseplaylistfeature.cpp @@ -23,6 +23,13 @@ #include "widget/wlibrary.h" #include "widget/wlibrarytextbrowser.h" +namespace { + +const ConfigKey kConfigKeyLastImportExportPlaylistDirectory( + "[Library]", "LastImportExportPlaylistDirectory"); + +} // anonymous namespace + BasePlaylistFeature::BasePlaylistFeature( Library* pLibrary, UserSettingsPointer pConfig, @@ -358,7 +365,7 @@ void BasePlaylistFeature::slotImportPlaylist() { // Update the import/export playlist directory QFileInfo fileName(playlist_file); - m_pConfig->set(ConfigKey("[Library]", "LastImportExportPlaylistDirectory"), + m_pConfig->set(kConfigKeyLastImportExportPlaylistDirectory, ConfigValue(fileName.dir().absolutePath())); slotImportPlaylistFile(playlist_file); @@ -404,7 +411,7 @@ void BasePlaylistFeature::slotCreateImportPlaylist() { // Set last import directory QFileInfo fileName(playlist_files.first()); - m_pConfig->set(ConfigKey("[Library]", "LastImportExportPlaylistDirectory"), + m_pConfig->set(kConfigKeyLastImportExportPlaylistDirectory, ConfigValue(fileName.dir().absolutePath())); int lastPlaylistId = -1; @@ -456,7 +463,7 @@ void BasePlaylistFeature::slotExportPlaylist() { qDebug() << "Export playlist" << playlistName; QString lastPlaylistDirectory = m_pConfig->getValue( - ConfigKey("[Library]", "LastImportExportPlaylistDirectory"), + kConfigKeyLastImportExportPlaylistDirectory, QStandardPaths::writableLocation(QStandardPaths::MusicLocation)); // Open a dialog to let the user choose the file location for playlist export. @@ -477,7 +484,7 @@ void BasePlaylistFeature::slotExportPlaylist() { } QFileInfo fileName(fileLocation); // Update the import/export playlist directory - m_pConfig->set(ConfigKey("[Library]", "LastImportExportPlaylistDirectory"), + m_pConfig->set(kConfigKeyLastImportExportPlaylistDirectory, ConfigValue(fileName.dir().absolutePath())); // The user has picked a new directory via a file dialog. This means the diff --git a/src/library/crate/cratefeature.cpp b/src/library/crate/cratefeature.cpp index da2e9eefe2a0..578597c9aa09 100644 --- a/src/library/crate/cratefeature.cpp +++ b/src/library/crate/cratefeature.cpp @@ -37,6 +37,9 @@ QString formatLabel( crateSummary.getTrackDurationText()); } +const ConfigKey kConfigKeyLastImportExportCrateDirectoryKey( + "[Library]", "LastImportExportCrateDirectory"); + } // anonymous namespace CrateFeature::CrateFeature(Library* pLibrary, @@ -571,8 +574,8 @@ void CrateFeature::slotImportPlaylist() { // Update the import/export crate directory QFileInfo fileName(playlist_file); - m_pConfig->set(ConfigKey("[Library]","LastImportExportCrateDirectory"), - ConfigValue(fileName.dir().absolutePath())); + m_pConfig->set(kConfigKeyLastImportExportCrateDirectoryKey, + ConfigValue(fileName.dir().absolutePath())); slotImportPlaylistFile(playlist_file); activateChild(m_lastRightClickedIndex); @@ -611,8 +614,8 @@ void CrateFeature::slotCreateImportCrate() { // Set last import directory QFileInfo fileName(playlist_files.first()); - m_pConfig->set(ConfigKey("[Library]","LastImportExportCrateDirectory"), - ConfigValue(fileName.dir().absolutePath())); + m_pConfig->set(kConfigKeyLastImportExportCrateDirectoryKey, + ConfigValue(fileName.dir().absolutePath())); CrateId lastCrateId; @@ -684,7 +687,7 @@ void CrateFeature::slotExportPlaylist() { } QString lastCrateDirectory = m_pConfig->getValue( - ConfigKey("[Library]", "LastImportExportCrateDirectory"), + kConfigKeyLastImportExportCrateDirectoryKey, QStandardPaths::writableLocation(QStandardPaths::MusicLocation)); QString fileFilter = tr("M3U Playlist (*.m3u)"); @@ -702,8 +705,8 @@ void CrateFeature::slotExportPlaylist() { } QFileInfo fileName(fileLocation); // Update the import/export crate directory - m_pConfig->set(ConfigKey("[Library]","LastImportExportCrateDirectory"), - ConfigValue(fileName.dir().absolutePath())); + m_pConfig->set(kConfigKeyLastImportExportCrateDirectoryKey, + ConfigValue(fileName.dir().absolutePath())); // The user has picked a new directory via a file dialog. This means the // system sandboxer (if we are sandboxed) has granted us permission to this