diff --git a/res/Icons.qrc b/res/Icons.qrc
index 3a7614f7..41db7cf5 100644
--- a/res/Icons.qrc
+++ b/res/Icons.qrc
@@ -97,6 +97,7 @@
icons/sound.png
icons/star.png
icons/table_edit.png
+ icons/table_save.png
icons/tick.png
icons/timeline_marker.png
icons/transmit.png
diff --git a/src/Config.h b/src/Config.h
index ef99e873..2cdd1172 100644
--- a/src/Config.h
+++ b/src/Config.h
@@ -30,7 +30,7 @@
#define VER_LAMEXP_MINOR_LO 4
#define VER_LAMEXP_TYPE Alpha
#define VER_LAMEXP_PATCH 13
-#define VER_LAMEXP_BUILD 866
+#define VER_LAMEXP_BUILD 867
///////////////////////////////////////////////////////////////////////////////
// Tool versions (minimum expected versions!)
diff --git a/src/Dialog_MainWindow.cpp b/src/Dialog_MainWindow.cpp
index b7e69784..de65afd3 100644
--- a/src/Dialog_MainWindow.cpp
+++ b/src/Dialog_MainWindow.cpp
@@ -125,6 +125,8 @@ MainWindow::MainWindow(FileListModel *fileListModel, AudioFileModel *metaInfo, S
m_showDetailsContextAction = m_sourceFilesContextMenu->addAction(QIcon(":/icons/zoom.png"), "N/A");
m_previewContextAction = m_sourceFilesContextMenu->addAction(QIcon(":/icons/sound.png"), "N/A");
m_findFileContextAction = m_sourceFilesContextMenu->addAction(QIcon(":/icons/folder_go.png"), "N/A");
+ m_sourceFilesContextMenu->addSeparator();
+ m_exportCsvContextAction = m_sourceFilesContextMenu->addAction(QIcon(":/icons/table_save.png"), "N/A");
SET_FONT_BOLD(m_showDetailsContextAction, true);
connect(buttonAddFiles, SIGNAL(clicked()), this, SLOT(addFilesButtonClicked()));
connect(buttonRemoveFile, SIGNAL(clicked()), this, SLOT(removeFileButtonClicked()));
@@ -141,6 +143,7 @@ MainWindow::MainWindow(FileListModel *fileListModel, AudioFileModel *metaInfo, S
connect(m_showDetailsContextAction, SIGNAL(triggered(bool)), this, SLOT(showDetailsButtonClicked()));
connect(m_previewContextAction, SIGNAL(triggered(bool)), this, SLOT(previewContextActionTriggered()));
connect(m_findFileContextAction, SIGNAL(triggered(bool)), this, SLOT(findFileContextActionTriggered()));
+ connect(m_exportCsvContextAction, SIGNAL(triggered(bool)), this, SLOT(exportCsvContextActionTriggered()));
//Setup "Output" tab
m_fileSystemModel = new QFileSystemModelEx();
@@ -703,6 +706,7 @@ void MainWindow::changeEvent(QEvent *e)
m_findFileContextAction->setText(tr("Browse File Location"));
m_showFolderContextAction->setText(tr("Browse Selected Folder"));
m_addFavoriteFolderAction->setText(tr("Bookmark Current Output Folder"));
+ m_exportCsvContextAction->setText(tr("Export Meta Tags to CSV File"));
//Force GUI update
m_metaInfoModel->clearData();
@@ -2127,6 +2131,51 @@ void MainWindow::handleDelayedFiles(void)
addFiles(selectedFiles);
}
+void MainWindow::exportCsvContextActionTriggered(void)
+{
+ TEMP_HIDE_DROPBOX
+ (
+ QString selectedCsvFile;
+
+ if(USE_NATIVE_FILE_DIALOG)
+ {
+ selectedCsvFile = QFileDialog::getSaveFileName(this, tr("Save CSV file"), m_settings->mostRecentInputPath(), QString("%1 (*.csv)").arg(tr("CSV File")));
+ }
+ else
+ {
+ QFileDialog dialog(this, tr("Save CSV file"));
+ dialog.setFileMode(QFileDialog::AnyFile);
+ dialog.setAcceptMode(QFileDialog::AcceptSave);
+ dialog.setNameFilter(QString("%1 (*.csv)").arg(tr("CSV File")));
+ dialog.setDirectory(m_settings->mostRecentInputPath());
+ if(dialog.exec())
+ {
+ selectedCsvFile = dialog.selectedFiles().first();
+ }
+ }
+
+ if(!selectedCsvFile.isEmpty())
+ {
+ m_settings->mostRecentInputPath(QFileInfo(selectedCsvFile).canonicalPath());
+ switch(m_fileListModel->exportToCsv(selectedCsvFile))
+ {
+ case 1:
+ QMessageBox::critical(this, tr("CSV Export"), NOBR(tr("There are no meta tags that could be exported!")));
+ break;
+ case 2:
+ QMessageBox::critical(this, tr("CSV Export"), NOBR(tr("Sorry, failed to open CSV file for writing!")));
+ break;
+ case 3:
+ QMessageBox::critical(this, tr("CSV Export"), NOBR(tr("Sorry, failed to write to the CSV file!")));
+ break;
+ default:
+ QMessageBox::information(this, tr("CSV Export"), NOBR(tr("The CSV files was created successfully!")));
+ break;
+ }
+ }
+ )
+}
+
/*
* Show or hide Drag'n'Drop notice after model reset
*/
diff --git a/src/Dialog_MainWindow.h b/src/Dialog_MainWindow.h
index 16c2eec3..08b67228 100644
--- a/src/Dialog_MainWindow.h
+++ b/src/Dialog_MainWindow.h
@@ -78,6 +78,7 @@ private slots:
void documentActionActivated(void);
void editMetaButtonClicked(void);
void encodeButtonClicked(void);
+ void exportCsvContextActionTriggered(void);
void fileDownButtonClicked(void);
void fileUpButtonClicked(void);
void findFileContextActionTriggered(void);
@@ -183,6 +184,7 @@ private:
QAction *m_showDetailsContextAction;
QAction *m_showFolderContextAction;
QAction *m_addFavoriteFolderAction;
+ QAction *m_exportCsvContextAction;
QActionGroup *m_languageActionGroup;
QActionGroup *m_styleActionGroup;
QActionGroup *m_tabActionGroup;
diff --git a/src/Model_FileList.cpp b/src/Model_FileList.cpp
index 73ce7f33..7ca633ff 100644
--- a/src/Model_FileList.cpp
+++ b/src/Model_FileList.cpp
@@ -23,6 +23,7 @@
#include
#include
+#include
////////////////////////////////////////////////////////////
// Constructor & Destructor
@@ -224,3 +225,73 @@ bool FileListModel::setFile(const QModelIndex &index, const AudioFileModel &audi
return false;
}
}
+
+int FileListModel::exportToCsv(const QString &outFile)
+{
+ const int nFiles = m_fileList.count();
+
+ bool havePosition = false, haveTitle = false, haveArtist = false, haveAlbum = false, haveGenre = false, haveYear = false, haveComment = false;
+
+ for(int i = 0; i < nFiles; i++)
+ {
+ if(m_fileList.at(i).filePosition() > 0) havePosition = true;
+ if(!m_fileList.at(i).fileName().isEmpty()) haveTitle = true;
+ if(!m_fileList.at(i).fileArtist().isEmpty()) haveArtist = true;
+ if(!m_fileList.at(i).fileAlbum().isEmpty()) haveAlbum = true;
+ if(!m_fileList.at(i).fileGenre().isEmpty()) haveGenre = true;
+ if(m_fileList.at(i).fileYear() > 0) haveYear = true;
+ if(!m_fileList.at(i).fileComment().isEmpty()) haveComment = true;
+ }
+
+ if(!(haveTitle || haveArtist || haveAlbum || haveGenre || haveYear || haveComment))
+ {
+ return 1;
+ }
+
+ QFile file(outFile);
+
+ if(file.open(QIODevice::WriteOnly))
+ {
+ QStringList line;
+
+ if(havePosition) line << "POSITION";
+ if(haveTitle) line << "TITLE";
+ if(haveArtist) line << "ARTIST";
+ if(haveAlbum) line << "ALBUM";
+ if(haveGenre) line << "GENRE";
+ if(haveYear) line << "YEAR";
+ if(haveComment) line << "COMMENT";
+
+ if(file.write(line.join(";").append("\r\n").toUtf8().prepend("\xef\xbb\xbf")) < 1)
+ {
+ file.close();
+ return 3;
+ }
+ }
+ else
+ {
+ return 2;
+ }
+
+ for(int i = 0; i < nFiles; i++)
+ {
+ QStringList line;
+
+ if(havePosition) line << QString::number(m_fileList.at(i).filePosition());
+ if(haveTitle) line << m_fileList.at(i).fileName().trimmed();
+ if(haveArtist) line << m_fileList.at(i).fileArtist().trimmed();
+ if(haveAlbum) line << m_fileList.at(i).fileAlbum().trimmed();
+ if(haveGenre) line << m_fileList.at(i).fileGenre().trimmed();
+ if(haveYear) line << QString::number(m_fileList.at(i).fileYear());
+ if(haveComment) line << m_fileList.at(i).fileComment().trimmed();
+
+ if(file.write(line.replaceInStrings(";", ",").join(";").append("\r\n").toUtf8()) < 1)
+ {
+ file.close();
+ return 3;
+ }
+ }
+
+ file.close();
+ return 0;
+}
diff --git a/src/Model_FileList.h b/src/Model_FileList.h
index 06f4fe19..d7ce173e 100644
--- a/src/Model_FileList.h
+++ b/src/Model_FileList.h
@@ -48,6 +48,9 @@ public:
bool setFile(const QModelIndex &index, const AudioFileModel &audioFile);
AudioFileModel &operator[] (const QModelIndex &index);
+ //CSV export/import
+ int exportToCsv(const QString &outFile);
+
public slots:
void addFile(const QString &filePath);
void addFile(const AudioFileModel &file);