Commit 91ff5907 authored by Urs Fleisch's avatar Urs Fleisch
Browse files

QML: Script for recursive CSV export, [feature-requests#42].

parent 47f759e7
......@@ -143,6 +143,8 @@ void UserActionsConfig::readFromConfig(ISettings* config)
UserActionsConfig::MenuCommand(QLatin1String("Resize Album Art"), QLatin1String("@qml %{qmlpath}/script/ResizeAlbumArt.qml"), false, true));
m_contextMenuCommands.push_back(
UserActionsConfig::MenuCommand(QLatin1String("Text Encoding ID3v1"), QLatin1String("@qml %{qmlpath}/script/ShowTextEncodingV1.qml"), false, true));
m_contextMenuCommands.push_back(
UserActionsConfig::MenuCommand(QLatin1String("Export CSV"), QLatin1String("@qml %{qmlpath}/script/ExportCsv.qml %{directory}/export.csv"), false, true));
}
#endif
}
......
......@@ -2191,12 +2191,21 @@ void Kid3Application::expandDirectory(const QModelIndex& index)
/**
* Expand the whole file list if GUI available.
* expandFileListFinished() is emitted when finished.
*/
void Kid3Application::requestExpandFileList()
{
emit expandFileListRequested();
}
/**
* Called when operation for requestExpandFileList() is finished.
*/
void Kid3Application::notifyExpandFileListFinished()
{
emit expandFileListFinished();
}
/**
* Process change of selection.
* The GUI is signaled to update the current selection and the controls.
......@@ -2832,7 +2841,17 @@ QVariantMap Kid3Application::getAllFrames(Frame::TagVersion tagMask) const
for (FrameCollection::const_iterator it = ft->frames().begin();
it != ft->frames().end();
++it) {
map.insert(it->getName(), it->getValue());
QString name(it->getName());
int nlPos = name.indexOf(QLatin1Char('\n'));
if (nlPos > 0) {
// probably "TXXX - User defined text information\nDescription" or
// "WXXX - User defined URL link\nDescription"
name = name.mid(nlPos + 1);
} else if (name.midRef(4, 3) == QLatin1String(" - ")) {
// probably "ID3-ID - Description"
name = name.left(4);
}
map.insert(name, it->getValue());
}
return map;
}
......
......@@ -983,6 +983,11 @@ public slots:
*/
void requestExpandFileList();
/**
* Called when operation for requestExpandFileList() is finished.
*/
void notifyExpandFileListFinished();
/**
* Process change of selection.
* The GUI is signaled to update the current selection and the controls.
......@@ -1171,6 +1176,12 @@ signals:
*/
void expandFileListRequested();
/**
* Emitted when operation requested by requestExpandFileList()
* (signal expandFileListRequested()) is finished.
*/
void expandFileListFinished();
/**
* Emitted when the file selection is changed.
* @see getFileSelectionRows()
......
......@@ -205,6 +205,16 @@ void TaggedFileSelection::setFilename(const QString& fn)
}
}
/**
* Get file path.
* @return absolute file path if single file selected, else null string.
*/
QString TaggedFileSelection::getFilePath() const
{
return m_state.m_singleFile
? m_state.m_singleFile->getAbsFilename() : QString();
}
/**
* Get string representation of detail information.
* @return information summary as string if single file else null string.
......
......@@ -55,6 +55,8 @@ class KID3_CORE_EXPORT TaggedFileSelection : public QObject {
/** File name if single file selected, else null string. */
Q_PROPERTY(QString fileName READ getFilename WRITE setFilename
NOTIFY singleFileChanged)
/** Absolute file path if single file selected, else null string. */
Q_PROPERTY(QString filePath READ getFilePath NOTIFY singleFileChanged)
/** Detail information if single file selected, else null string. */
Q_PROPERTY(QString detailInfo READ getDetailInfo NOTIFY singleFileChanged)
/** Format of tag 1 if single file selected, else null string. */
......@@ -144,6 +146,12 @@ public:
*/
void setFilename(const QString& fn);
/**
* Get file path.
* @return absolute file path if single file selected, else null string.
*/
QString getFilePath() const;
/**
* Get string representation of detail information.
* @return information summary as string if single file else null string.
......
......@@ -104,7 +104,8 @@ BaseMainWindowImpl::BaseMainWindowImpl(QMainWindow* mainWin,
#if defined HAVE_PHONON || QT_VERSION >= 0x050000
m_playToolBar(0),
#endif
m_editFrameTaggedFile(0), m_findReplaceActive(false)
m_editFrameTaggedFile(0), m_findReplaceActive(false),
m_expandNotificationNeeded(false)
{
ContextHelp::init(m_platformTools);
......@@ -1150,6 +1151,7 @@ void BaseMainWindowImpl::toggleExpanded(const QModelIndex& index)
*/
void BaseMainWindowImpl::expandFileList()
{
m_expandNotificationNeeded = sender() == m_app;
m_expandFileListStartTime = QDateTime::currentDateTime();
connect(m_app->getFileProxyModelIterator(),
SIGNAL(nextReady(QPersistentModelIndex)),
......@@ -1204,6 +1206,10 @@ void BaseMainWindowImpl::expandNextDirectory(const QPersistentModelIndex& index)
if (m_progressDialog) {
m_progressDialog->reset();
}
if (m_expandNotificationNeeded) {
m_expandNotificationNeeded = false;
m_app->notifyExpandFileListFinished();
}
}
}
......
......@@ -468,6 +468,7 @@ private:
TaggedFile* m_editFrameTaggedFile;
QDateTime m_expandFileListStartTime;
bool m_findReplaceActive;
bool m_expandNotificationNeeded;
};
......
/**
* \file ExportAll.qml
* Export all tags of all files to a CSV file.
*
* \b Project: Kid3
* \author Urs Fleisch
* \date 06 Mar 2015
*
* Copyright (C) 2015 Urs Fleisch
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import Kid3 1.0
Kid3Script {
onRun: {
var columnSet = {}
var rows = []
function doWork() {
var tags
var prop
if (app.selectionInfo.tagFormatV2) {
tags = app.getAllFrames(tagv2)
}
if (app.selectionInfo.tagFormatV1) {
var tagsV1 = app.getAllFrames(tagv1)
if (typeof tags === "undefined") {
tags = {}
}
for (prop in tagsV1) {
tags["v1" + prop] = tagsV1[prop]
}
}
if (tags) {
rows.push(tags)
for (prop in tags) {
columnSet[prop] = null
}
tags["File Path"] = app.selectionInfo.filePath
}
if (!app.nextFile()) {
var columns = []
for (prop in columnSet) {
columns.push(prop)
}
columns.sort()
columns.unshift("File Path")
var numRows = rows.length
var numColumns = columns.length
var columnNr, rowNr
var txt = ""
for (columnNr = 0; columnNr < numColumns; ++columnNr) {
if (columnNr > 0) {
txt += "\t"
}
txt += columns[columnNr]
}
txt += "\n"
for (rowNr = 0; rowNr < numRows; ++rowNr) {
var row = rows[rowNr]
for (columnNr = 0; columnNr < numColumns; ++columnNr) {
var value = row[columns[columnNr]]
if (typeof value === "undefined") {
value = ""
} else {
value = value.replace(/\n/g, "\\n").replace(/\r/g, "\\r").
replace(/\t/g, "\\t")
}
if (columnNr > 0) {
txt += "\t"
}
txt += value
}
txt += "\n"
}
var exportPath = getArguments()[0]
if (!exportPath) {
exportPath = script.tempPath() + "/export.csv"
}
if (script.writeFile(exportPath, txt)) {
console.log("Exported tags of %1 files to %2".
arg(numRows).arg(exportPath))
} else {
console.log("Failed to write", exportPath)
}
Qt.quit()
} else {
setTimeout(doWork, 1)
}
}
function startWork() {
app.expandFileListFinished.disconnect(startWork)
console.log("Reading tags")
app.firstFile()
doWork()
}
if (!isStandalone()) {
console.log("Expanding file list")
app.expandFileListFinished.connect(startWork)
app.requestExpandFileList()
} else {
startWork()
}
}
}
......@@ -3,4 +3,5 @@ set (script_QML_SRCS
script/ResizeAlbumArt.qml
script/QmlConsole.qml
script/ShowTextEncodingV1.qml
script/ExportCsv.qml
)
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment