updated renaming utility
- allow usage of QJSEngine instead of deprecated QScriptEngine - moved variables and functions from global object to tageditor object
This commit is contained in:
parent
10bfa8aeea
commit
1c4d577264
|
@ -60,7 +60,8 @@ set(WIDGETS_HEADER_FILES
|
|||
renamingutility/filesystemitemmodel.h
|
||||
renamingutility/filteredfilesystemitemmodel.h
|
||||
renamingutility/renamingengine.h
|
||||
renamingutility/scriptfunctions.h
|
||||
renamingutility/scriptdefs.h
|
||||
renamingutility/tageditorobject.h
|
||||
)
|
||||
set(WIDGETS_SRC_FILES
|
||||
gui/attachmentsedit.cpp
|
||||
|
@ -77,7 +78,6 @@ set(WIDGETS_SRC_FILES
|
|||
gui/infowidgetbase.cpp
|
||||
gui/initiate.cpp
|
||||
gui/javascripthighlighter.cpp
|
||||
gui/previousvaluehandling.cpp
|
||||
gui/renamefilesdialog.cpp
|
||||
gui/settingsdialog.cpp
|
||||
gui/tagedit.cpp
|
||||
|
@ -86,7 +86,7 @@ set(WIDGETS_SRC_FILES
|
|||
renamingutility/filesystemitemmodel.cpp
|
||||
renamingutility/filteredfilesystemitemmodel.cpp
|
||||
renamingutility/renamingengine.cpp
|
||||
renamingutility/scriptfunctions.cpp
|
||||
renamingutility/tageditorobject.h
|
||||
resources/icons.qrc
|
||||
resources/scripts.qrc
|
||||
)
|
||||
|
|
|
@ -113,7 +113,10 @@ Here are some Bash examples which illustrate getting and setting tag information
|
|||
## Build instructions
|
||||
The application depends on c++utilities, qtutilities and tagparser and is built in the same way as these libaries.
|
||||
|
||||
The following Qt 5 modules are requried: core gui script widgets webenginewidgets/webkitwidgets
|
||||
The following Qt 5 modules are requried: core gui qml/script widgets webenginewidgets/webkitwidgets
|
||||
|
||||
If script is installed on the system, the editor will link against it. Otherwise it will link against qml.
|
||||
To force usage of qml add "CONFIG+=forcejsengine" to the qmake arguments.
|
||||
|
||||
If webkitwidgets is installed on the system, the editor will link against it. Otherwise it will link against webenginewidgets.
|
||||
To force usage of webenginewidgets add "CONFIG+=forcewebengine" to the qmake arguments.
|
||||
|
|
|
@ -4,11 +4,6 @@
|
|||
|
||||
namespace QtGui {
|
||||
|
||||
/*
|
||||
TRANSLATOR QtGui::FileFilterProxyModel
|
||||
Necessary for lupdate.
|
||||
*/
|
||||
|
||||
FileFilterProxyModel::FileFilterProxyModel(QObject *parent) :
|
||||
QSortFilterProxyModel(parent),
|
||||
m_filterEnabled(true)
|
||||
|
|
|
@ -23,11 +23,6 @@ using namespace Media;
|
|||
|
||||
namespace QtGui {
|
||||
|
||||
/*
|
||||
TRANSLATOR QtGui::InfoWidgetBase
|
||||
Necessary for lupdate.
|
||||
*/
|
||||
|
||||
InfoWidgetBase::InfoWidgetBase(QWidget *parent) :
|
||||
QWidget(parent),
|
||||
m_notificationModel(nullptr)
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
// include configuration from separate header file when building with CMake
|
||||
#ifndef APP_METADATA_AVAIL
|
||||
#include "resources/config.h"
|
||||
# include "resources/config.h"
|
||||
#endif
|
||||
|
||||
#include <qtutilities/resources/qtconfigarguments.h>
|
||||
|
|
|
@ -64,11 +64,6 @@ using namespace Widgets;
|
|||
|
||||
namespace QtGui {
|
||||
|
||||
/*
|
||||
TRANSLATOR QtGui::MainWindow
|
||||
Necessary for lupdate.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief The LoadingResult enum specifies whether the file could be parsed.
|
||||
*/
|
||||
|
|
|
@ -27,9 +27,6 @@ NotificationLabel::NotificationLabel(QWidget *parent) :
|
|||
m_updateTimer.setInterval(80);
|
||||
}
|
||||
|
||||
NotificationLabel::~NotificationLabel()
|
||||
{}
|
||||
|
||||
void NotificationLabel::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
QStyle *style = QWidget::style();
|
||||
|
|
|
@ -33,7 +33,6 @@ class NotificationLabel : public QWidget
|
|||
Q_PROPERTY(int maxIconSize READ maxIconSize WRITE setMaxIconSize)
|
||||
public:
|
||||
explicit NotificationLabel(QWidget *parent = nullptr);
|
||||
virtual ~NotificationLabel();
|
||||
|
||||
const QString &text() const;
|
||||
NotificationType notificationType() const;
|
||||
|
|
|
@ -12,11 +12,6 @@ using namespace Media;
|
|||
|
||||
namespace QtGui {
|
||||
|
||||
/*
|
||||
TRANSLATOR QtGui::NotificationModel
|
||||
Necessary for lupdate.
|
||||
*/
|
||||
|
||||
NotificationModel::NotificationModel(QObject *parent) :
|
||||
QAbstractListModel(parent)
|
||||
{}
|
||||
|
|
|
@ -15,18 +15,10 @@ using namespace Widgets;
|
|||
|
||||
namespace QtGui {
|
||||
|
||||
/*
|
||||
TRANSLATOR QtGui::PathLineEdit
|
||||
Necessary for lupdate.
|
||||
*/
|
||||
|
||||
PathLineEdit::PathLineEdit(QWidget *parent) :
|
||||
ClearLineEdit(parent)
|
||||
{}
|
||||
|
||||
PathLineEdit::~PathLineEdit()
|
||||
{}
|
||||
|
||||
QAbstractItemModel *PathLineEdit::completionModel() const
|
||||
{
|
||||
if(QCompleter *c = completer()) {
|
||||
|
|
|
@ -18,7 +18,6 @@ class PathLineEdit : public Widgets::ClearLineEdit
|
|||
|
||||
public:
|
||||
explicit PathLineEdit(QWidget *parent = nullptr);
|
||||
virtual ~PathLineEdit();
|
||||
|
||||
QAbstractItemModel *completionModel() const;
|
||||
void setCompletionModel(QAbstractItemModel *model);
|
||||
|
|
|
@ -35,11 +35,6 @@ using namespace Media;
|
|||
|
||||
namespace QtGui {
|
||||
|
||||
/*
|
||||
TRANSLATOR QtGui::PicturePreviewSelection
|
||||
Necessary for lupdate.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Constructs a new PicturePreviewSelection for the specified \a tag and \a field.
|
||||
*/
|
||||
|
@ -65,7 +60,7 @@ PicturePreviewSelection::PicturePreviewSelection(Tag *tag, KnownField field, QWi
|
|||
}
|
||||
|
||||
/*!
|
||||
* \brief Destroys the PicturePreviewSelection.
|
||||
* \brief Destroys the instance.
|
||||
*/
|
||||
PicturePreviewSelection::~PicturePreviewSelection()
|
||||
{}
|
||||
|
|
|
@ -35,7 +35,7 @@ class PicturePreviewSelection : public QWidget
|
|||
|
||||
public:
|
||||
explicit PicturePreviewSelection(Media::Tag *tag = nullptr, Media::KnownField field = Media::KnownField::Invalid, QWidget *parent = nullptr);
|
||||
virtual ~PicturePreviewSelection();
|
||||
~PicturePreviewSelection();
|
||||
|
||||
Media::Tag *tag() const;
|
||||
Media::KnownField field() const;
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
#include "./previousvaluehandling.h"
|
||||
|
||||
namespace QtGui {
|
||||
|
||||
}
|
|
@ -13,7 +13,6 @@
|
|||
#include <QMessageBox>
|
||||
#include <QFileDialog>
|
||||
#include <QDir>
|
||||
#include <QScriptEngine>
|
||||
#include <QItemSelectionModel>
|
||||
#include <QMenu>
|
||||
#include <QClipboard>
|
||||
|
@ -26,11 +25,6 @@ using namespace RenamingUtility;
|
|||
|
||||
namespace QtGui {
|
||||
|
||||
/*
|
||||
TRANSLATOR QtGui::RenameFilesDialog
|
||||
Necessary for lupdate.
|
||||
*/
|
||||
|
||||
RenameFilesDialog::RenameFilesDialog(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
m_ui(new Ui::RenameFilesDialog),
|
||||
|
@ -44,7 +38,7 @@ RenameFilesDialog::RenameFilesDialog(QWidget *parent) :
|
|||
setStyleSheet(dialogStyle() + QStringLiteral("QSplitter:handle { background-color: palette(base); }"));
|
||||
#endif
|
||||
// setup javascript editor and script file selection
|
||||
QFont font("Courier", 10);
|
||||
QFont font(QStringLiteral("Courier"), 10);
|
||||
font.setFixedPitch(true);
|
||||
m_ui->javaScriptPlainTextEdit->setFont(font);
|
||||
m_highlighter = new JavaScriptHighlighter(m_ui->javaScriptPlainTextEdit->document());
|
||||
|
@ -124,7 +118,6 @@ void RenameFilesDialog::startGeneratingPreview()
|
|||
QDir selectedDir(directory());
|
||||
m_ui->notificationLabel->setHidden(false);
|
||||
if(selectedDir.exists()) {
|
||||
QScriptEngine engine;
|
||||
QString program;
|
||||
if(m_ui->sourceFileStackedWidget->currentIndex() == 0) {
|
||||
program = m_ui->javaScriptPlainTextEdit->toPlainText();
|
||||
|
@ -143,18 +136,17 @@ void RenameFilesDialog::startGeneratingPreview()
|
|||
}
|
||||
}
|
||||
if(!program.isEmpty()) {
|
||||
QScriptSyntaxCheckResult res = engine.checkSyntax(program);
|
||||
if(res.state() != QScriptSyntaxCheckResult::Error) {
|
||||
if(m_engine->setProgram(program)) {
|
||||
m_ui->notificationLabel->setText(tr("Generating preview ..."));
|
||||
m_ui->notificationLabel->setNotificationType(NotificationType::Progress);
|
||||
m_ui->abortClosePushButton->setText(tr("Abort"));
|
||||
m_ui->generatePreviewPushButton->setHidden(true);
|
||||
m_ui->applyChangingsPushButton->setHidden(true);
|
||||
m_engine->generatePreview(program, directory(), m_ui->includeSubdirsCheckBox->isChecked());
|
||||
m_engine->generatePreview(directory(), m_ui->includeSubdirsCheckBox->isChecked());
|
||||
} else {
|
||||
m_engine->clearPreview();
|
||||
m_ui->notificationLabel->setText(tr("The script is not valid.\nError in line %1 and column %2:\n %3")
|
||||
.arg(res.errorLineNumber()).arg(res.errorColumnNumber()).arg(res.errorMessage()));
|
||||
m_ui->notificationLabel->setText(tr("The script is not valid.\nError in line %1: %3")
|
||||
.arg(m_engine->errorLineNumber()).arg(m_engine->errorMessage()));
|
||||
m_ui->notificationLabel->setNotificationType(NotificationType::Warning);
|
||||
}
|
||||
} else {
|
||||
|
@ -191,7 +183,7 @@ void RenameFilesDialog::showPreviewProgress(int itemsProcessed, int errorsOccure
|
|||
m_errorsOccured = errorsOccured;
|
||||
QString text = tr("%1 files/directories processed", 0, itemsProcessed).arg(itemsProcessed);
|
||||
if(m_errorsOccured > 0) {
|
||||
text.append(QStringLiteral("\n"));
|
||||
text.append(QChar('\n'));
|
||||
text.append(tr("%1 error(s) occured", 0, errorsOccured).arg(errorsOccured));
|
||||
}
|
||||
m_ui->notificationLabel->setText(text);
|
||||
|
|
|
@ -20,11 +20,6 @@ using namespace Media;
|
|||
|
||||
namespace QtGui {
|
||||
|
||||
/*
|
||||
TRANSLATOR QtGui::TagEdit
|
||||
Necessary for lupdate.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \class QtGui::TagEdit
|
||||
* \brief The TagEdit widget allows the user to edit Media::Tag objects.
|
||||
|
@ -55,14 +50,6 @@ TagEdit::TagEdit(QWidget *parent) :
|
|||
setLayout(mainLayout);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Destroys the tag edit.
|
||||
*
|
||||
* Does not destroy assigned tags.
|
||||
*/
|
||||
TagEdit::~TagEdit()
|
||||
{}
|
||||
|
||||
/*!
|
||||
* \brief Assigns the specified \a tag to the edit.
|
||||
* \param updateUi Specifies whether the UI of should be updated.
|
||||
|
|
|
@ -31,7 +31,6 @@ class TagEdit : public QWidget
|
|||
|
||||
public:
|
||||
explicit TagEdit(QWidget *parent = nullptr);
|
||||
~TagEdit();
|
||||
const QList<Media::Tag *> &tags() const;
|
||||
void setTag(Media::Tag *tag, bool updateUi = true);
|
||||
void setTags(const QList<Media::Tag *> &tags, bool updateUi = true);
|
||||
|
|
|
@ -49,11 +49,6 @@ using namespace ConversionUtilities;
|
|||
|
||||
namespace QtGui {
|
||||
|
||||
/*
|
||||
TRANSLATOR QtGui::TagFieldEdit
|
||||
Necessary for lupdate.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \class QtGui::TagFieldEdit
|
||||
* \brief The TagFieldEdit widget allows the user to edit a specified tag field.
|
||||
|
@ -83,14 +78,6 @@ TagFieldEdit::TagFieldEdit(const QList<Media::Tag *> &tags, Media::KnownField fi
|
|||
updateValue();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Destroys the object.
|
||||
*
|
||||
* Does not destroy the assigned tags.
|
||||
*/
|
||||
TagFieldEdit::~TagFieldEdit()
|
||||
{}
|
||||
|
||||
/*!
|
||||
* \brief Assigns the specified \a tags and sets the specified \a fields using the given \a previousValueHandling.
|
||||
*
|
||||
|
|
|
@ -39,7 +39,6 @@ class TagFieldEdit : public QWidget
|
|||
|
||||
public:
|
||||
explicit TagFieldEdit(const QList<Media::Tag *> &tags, Media::KnownField field, QWidget *parent = nullptr);
|
||||
virtual ~TagFieldEdit();
|
||||
|
||||
const QList<Media::Tag *> &tags() const;
|
||||
Media::KnownField field() const;
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
namespace RenamingUtility {
|
||||
|
||||
enum class ActionType {
|
||||
None,
|
||||
Rename,
|
||||
Skip
|
||||
};
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
#include "./renamingengine.h"
|
||||
#include "./filesystemitemmodel.h"
|
||||
#include "./filteredfilesystemitemmodel.h"
|
||||
#include "./scriptfunctions.h"
|
||||
#include "./tageditorobject.h"
|
||||
|
||||
#include <c++utilities/misc/memory.h>
|
||||
|
||||
#include <QDir>
|
||||
#include <QScriptEngine>
|
||||
#include <QScriptProgram>
|
||||
#include <QStringBuilder>
|
||||
|
||||
#include <thread>
|
||||
|
||||
|
@ -15,14 +14,10 @@ using namespace std;
|
|||
|
||||
namespace RenamingUtility {
|
||||
|
||||
/*
|
||||
TRANSLATOR RenamingUtility::RemamingEngine
|
||||
Necessary for lupdate.
|
||||
*/
|
||||
|
||||
RemamingEngine::RemamingEngine(QObject *parent) :
|
||||
QObject(parent),
|
||||
m_go(m_engine.globalObject()),
|
||||
m_tagEditorQObj(new TagEditorObject(&m_engine)),
|
||||
m_tagEditorJsObj(TAGEDITOR_JS_QOBJECT(m_engine, m_tagEditorQObj)),
|
||||
m_itemsProcessed(0),
|
||||
m_errorsOccured(0),
|
||||
m_aborted(false),
|
||||
|
@ -31,21 +26,40 @@ RemamingEngine::RemamingEngine(QObject *parent) :
|
|||
m_currentModel(nullptr),
|
||||
m_previewModel(nullptr)
|
||||
{
|
||||
m_engine.globalObject().setProperty(QStringLiteral("tageditor"), m_tagEditorJsObj);
|
||||
connect(this, &RemamingEngine::previewGenerated, this, &RemamingEngine::processPreviewGenerated);
|
||||
connect(this, &RemamingEngine::changingsApplied, this, &RemamingEngine::processChangingsApplied);
|
||||
}
|
||||
|
||||
RemamingEngine::~RemamingEngine()
|
||||
{}
|
||||
bool RemamingEngine::setProgram(const TAGEDITOR_JS_VALUE &program)
|
||||
{
|
||||
if(TAGEDITOR_JS_IS_VALID_PROG(program)) {
|
||||
m_errorMessage.clear();
|
||||
m_errorLineNumber = 0;
|
||||
m_program = program;
|
||||
return true;
|
||||
} else if(program.isError()) {
|
||||
m_errorMessage = program.property(QStringLiteral("message")).toString();
|
||||
m_errorLineNumber = TAGEDITOR_JS_INT(program.property(QStringLiteral("lineNumber")));
|
||||
} else {
|
||||
m_errorMessage = tr("Program is not callable.");
|
||||
m_errorLineNumber = 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RemamingEngine::generatePreview(const QScriptProgram &scriptProgram, const QDir &rootDirectory, bool includeSubdirs)
|
||||
bool RemamingEngine::setProgram(const QString &program)
|
||||
{
|
||||
return setProgram(m_engine.evaluate(QStringLiteral("(function(){") % program % QStringLiteral("})")));
|
||||
}
|
||||
|
||||
bool RemamingEngine::generatePreview(const QDir &rootDirectory, bool includeSubdirs)
|
||||
{
|
||||
if(!m_mutex.try_lock()) {
|
||||
return false;
|
||||
}
|
||||
lock_guard<mutex> guard(m_mutex, adopt_lock);
|
||||
setRootItem();
|
||||
m_program = scriptProgram;
|
||||
m_includeSubdirs = includeSubdirs;
|
||||
m_dir = rootDirectory;
|
||||
auto startFunc = [this] () {
|
||||
|
@ -54,7 +68,6 @@ bool RemamingEngine::generatePreview(const QScriptProgram &scriptProgram, const
|
|||
m_aborted.store(false);
|
||||
m_itemsProcessed = 0;
|
||||
m_errorsOccured = 0;
|
||||
m_go.setProperty("persistent", m_persistent = m_engine.newObject(), QScriptValue::Undeletable);
|
||||
m_newlyGeneratedRootItem = generatePreview(m_dir);
|
||||
}
|
||||
emit previewGenerated();
|
||||
|
@ -174,8 +187,7 @@ unique_ptr<FileSystemItem> RemamingEngine::generatePreview(const QDir &dir, File
|
|||
{
|
||||
auto item = make_unique<FileSystemItem>(ItemStatus::Current, ItemType::Dir, dir.dirName(), parent);
|
||||
item->setApplied(false);
|
||||
QFileInfoList entries = dir.entryInfoList();
|
||||
foreach(const QFileInfo &entry, entries) {
|
||||
for(const QFileInfo &entry : dir.entryInfoList()) {
|
||||
if(entry.fileName() == QLatin1String("..")
|
||||
|| entry.fileName() == QLatin1String(".")) {
|
||||
continue;
|
||||
|
@ -280,7 +292,7 @@ void RemamingEngine::applyChangings(FileSystemItem *parentItem)
|
|||
|
||||
void RemamingEngine::setError(const QList<FileSystemItem *> items)
|
||||
{
|
||||
foreach(FileSystemItem *item, items) {
|
||||
for(FileSystemItem *item : items) {
|
||||
item->setErrorOccured(true);
|
||||
item->setNote(tr("skipped due to error of superior item"));
|
||||
}
|
||||
|
@ -288,33 +300,30 @@ void RemamingEngine::setError(const QList<FileSystemItem *> items)
|
|||
|
||||
void RemamingEngine::executeScriptForItem(const QFileInfo &fileInfo, FileSystemItem *item)
|
||||
{
|
||||
// make file info for the specified item available in the script
|
||||
m_tagEditorQObj->setFileInfo(fileInfo, item);
|
||||
// execute script
|
||||
setupGlobalObject(fileInfo, item);
|
||||
QScriptValue res = m_engine.evaluate(m_program);
|
||||
if(m_engine.hasUncaughtException()) {
|
||||
auto scriptResult = m_program.call();
|
||||
if(scriptResult.isError()) {
|
||||
// handle error
|
||||
item->setErrorOccured(true);
|
||||
item->setNote(res.toString());
|
||||
m_engine.clearExceptions();
|
||||
item->setNote(scriptResult.toString());
|
||||
} else {
|
||||
// create preview for action
|
||||
QScriptValue newName = m_go.property("newName");
|
||||
QScriptValue newRelativeDirectory = m_go.property("newRelativeDirectory");
|
||||
ActionType action = ActionType::Skip;
|
||||
if(m_go.property("action").isNumber()) {
|
||||
action = static_cast<ActionType>(m_go.property("action").toInt32());
|
||||
}
|
||||
switch(action) {
|
||||
const QString &newName = m_tagEditorQObj->newName();
|
||||
const QString &newRelativeDirectory = m_tagEditorQObj->newRelativeDirectory();
|
||||
switch(m_tagEditorQObj->action()) {
|
||||
case ActionType::None:
|
||||
item->setNote(tr("no action specified"));
|
||||
break;
|
||||
case ActionType::Rename:
|
||||
if(newRelativeDirectory.isString()) {
|
||||
FileSystemItem *counterpartParent = item->root()->makeChildAvailable(newRelativeDirectory.toString());
|
||||
if(!newRelativeDirectory.isEmpty()) {
|
||||
FileSystemItem *counterpartParent = item->root()->makeChildAvailable(newRelativeDirectory);
|
||||
if(counterpartParent->status() == ItemStatus::New
|
||||
&& counterpartParent->note().isEmpty()) {
|
||||
counterpartParent->setNote(tr("will be created"));
|
||||
}
|
||||
QString counterpartName = newName.isString()
|
||||
? newName.toString()
|
||||
: item->name();
|
||||
const QString &counterpartName = newName.isEmpty() ? item->name() : newName;
|
||||
if(counterpartParent->findChild(counterpartName, item)) {
|
||||
item->setNote(tr("name is already used at new location"));
|
||||
item->setErrorOccured(true);
|
||||
|
@ -324,8 +333,8 @@ void RemamingEngine::executeScriptForItem(const QFileInfo &fileInfo, FileSystemI
|
|||
counterpart->setCheckable(true);
|
||||
counterpart->setChecked(true);
|
||||
}
|
||||
} else if(newName.isString()) {
|
||||
item->setNewName(newName.toString());
|
||||
} else if(!newName.isEmpty()) {
|
||||
item->setNewName(newName);
|
||||
}
|
||||
if(FileSystemItem *newItem = item->counterpart()) {
|
||||
if((newItem->name().isEmpty() || newItem->name() == item->name())
|
||||
|
@ -347,34 +356,8 @@ void RemamingEngine::executeScriptForItem(const QFileInfo &fileInfo, FileSystemI
|
|||
break;
|
||||
default:
|
||||
item->setNote(tr("skipped"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RemamingEngine::setupGlobalObject(const QFileInfo &file, FileSystemItem *item)
|
||||
{
|
||||
// create new global object to clean previous variables ...
|
||||
m_go = m_engine.newObject();
|
||||
// ... except the persistent object
|
||||
m_go.setProperty("persistent", m_persistent, QScriptValue::Undeletable);
|
||||
// provide properties/functions
|
||||
m_go.setProperty("currentPath", file.absoluteFilePath(), QScriptValue::ReadOnly);
|
||||
m_go.setProperty("currentName", item->name(), QScriptValue::ReadOnly);
|
||||
m_go.setProperty("currentRelativeDirectory", item->relativeDir(), QScriptValue::ReadOnly);
|
||||
m_go.setProperty("isDir", item->type() == ItemType::Dir, QScriptValue::ReadOnly);
|
||||
m_go.setProperty("isFile", item->type() == ItemType::File, QScriptValue::ReadOnly);
|
||||
m_go.setProperty("action", QScriptValue(static_cast<int>(ActionType::Rename)), QScriptValue::Undeletable);
|
||||
m_go.setProperty("parseFileInfo", m_engine.newFunction(ScriptFunctions::parseFileInfo), QScriptValue::ReadOnly);
|
||||
m_go.setProperty("parseFileName", m_engine.newFunction(ScriptFunctions::parseFileName), QScriptValue::ReadOnly);
|
||||
m_go.setProperty("allFiles", m_engine.newFunction(ScriptFunctions::allFiles), QScriptValue::ReadOnly);
|
||||
m_go.setProperty("firstFile", m_engine.newFunction(ScriptFunctions::firstFile), QScriptValue::ReadOnly);
|
||||
m_go.setProperty("writeLog", m_engine.newFunction(ScriptFunctions::writeLog), QScriptValue::ReadOnly);
|
||||
QScriptValue actionObject = m_engine.newObject();
|
||||
actionObject.setProperty("rename", QScriptValue(static_cast<int>(ActionType::Rename)), QScriptValue::ReadOnly);
|
||||
actionObject.setProperty("skip", QScriptValue(static_cast<int>(ActionType::Skip)), QScriptValue::ReadOnly);
|
||||
m_go.setProperty("actionType", actionObject, QScriptValue::ReadOnly);
|
||||
m_engine.setGlobalObject(m_go);
|
||||
}
|
||||
|
||||
} // namespace RenamingUtility
|
||||
|
|
|
@ -2,26 +2,31 @@
|
|||
#define RENAMINGUTILITY_RENAMINGENGINE_H
|
||||
|
||||
#include "./filesystemitem.h"
|
||||
#include "./scriptdefs.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
#include <QDir>
|
||||
#include <QScriptProgram>
|
||||
#include <QScriptEngine>
|
||||
#include <QScriptValue>
|
||||
|
||||
#if TAGEDITOR_USE_JSENGINE
|
||||
# include <QJSEngine>
|
||||
# include <QJSValue>
|
||||
#else
|
||||
# include <QScriptEngine>
|
||||
# include <QScriptValue>
|
||||
#endif
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <atomic>
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QFileInfo)
|
||||
QT_FORWARD_DECLARE_CLASS(QScriptProgram)
|
||||
QT_FORWARD_DECLARE_CLASS(QScriptContext)
|
||||
|
||||
namespace RenamingUtility {
|
||||
|
||||
class FileSystemItemModel;
|
||||
class FilteredFileSystemItemModel;
|
||||
class TagEditorObject;
|
||||
|
||||
class RemamingEngine : public QObject
|
||||
{
|
||||
|
@ -29,10 +34,11 @@ class RemamingEngine : public QObject
|
|||
|
||||
public:
|
||||
RemamingEngine(QObject *parent = nullptr);
|
||||
virtual ~RemamingEngine();
|
||||
|
||||
FileSystemItem *rootItem() const;
|
||||
const QScriptProgram &scriptProgram() const;
|
||||
const TAGEDITOR_JS_VALUE &scriptProgram() const;
|
||||
bool setProgram(const TAGEDITOR_JS_VALUE &program);
|
||||
bool setProgram(const QString &program);
|
||||
const QDir &rootDirectory() const;
|
||||
bool subdirsIncluded() const;
|
||||
bool isBusy();
|
||||
|
@ -41,9 +47,11 @@ public:
|
|||
FileSystemItemModel *model();
|
||||
FilteredFileSystemItemModel *currentModel();
|
||||
FilteredFileSystemItemModel *previewModel();
|
||||
const QString &errorMessage() const;
|
||||
int errorLineNumber() const;
|
||||
|
||||
public slots:
|
||||
bool generatePreview(const QScriptProgram &scriptProgram, const QDir &rootDirectory, bool includeSubdirs);
|
||||
bool generatePreview(const QDir &rootDirectory, bool includeSubdirs);
|
||||
bool applyChangings();
|
||||
void abort();
|
||||
|
||||
|
@ -63,23 +71,24 @@ private:
|
|||
void applyChangings(FileSystemItem *parentItem);
|
||||
static void setError(const QList<FileSystemItem *> items);
|
||||
void executeScriptForItem(const QFileInfo &fileInfo, FileSystemItem *item);
|
||||
void setupGlobalObject(const QFileInfo &file, FileSystemItem *item);
|
||||
|
||||
QScriptEngine m_engine;
|
||||
QScriptValue m_go;
|
||||
QScriptValue m_persistent;
|
||||
TagEditorObject *m_tagEditorQObj;
|
||||
TAGEDITOR_JS_ENGINE m_engine;
|
||||
TAGEDITOR_JS_VALUE m_tagEditorJsObj;
|
||||
std::unique_ptr<FileSystemItem> m_rootItem;
|
||||
std::unique_ptr<FileSystemItem> m_newlyGeneratedRootItem;
|
||||
int m_itemsProcessed;
|
||||
int m_errorsOccured;
|
||||
std::atomic<bool> m_aborted;
|
||||
QScriptProgram m_program;
|
||||
TAGEDITOR_JS_VALUE m_program;
|
||||
QDir m_dir;
|
||||
bool m_includeSubdirs;
|
||||
std::mutex m_mutex;
|
||||
FileSystemItemModel *m_model;
|
||||
FilteredFileSystemItemModel *m_currentModel;
|
||||
FilteredFileSystemItemModel *m_previewModel;
|
||||
QString m_errorMessage;
|
||||
int m_errorLineNumber;
|
||||
};
|
||||
|
||||
inline FileSystemItem *RemamingEngine::rootItem() const
|
||||
|
@ -87,7 +96,7 @@ inline FileSystemItem *RemamingEngine::rootItem() const
|
|||
return m_rootItem.get();
|
||||
}
|
||||
|
||||
inline const QScriptProgram &RemamingEngine::scriptProgram() const
|
||||
inline const TAGEDITOR_JS_VALUE &RemamingEngine::scriptProgram() const
|
||||
{
|
||||
return m_program;
|
||||
}
|
||||
|
@ -102,6 +111,16 @@ inline bool RemamingEngine::subdirsIncluded() const
|
|||
return m_includeSubdirs;
|
||||
}
|
||||
|
||||
inline const QString &RemamingEngine::errorMessage() const
|
||||
{
|
||||
return m_errorMessage;
|
||||
}
|
||||
|
||||
inline int RemamingEngine::errorLineNumber() const
|
||||
{
|
||||
return m_errorLineNumber;
|
||||
}
|
||||
|
||||
} // namespace RenamingUtility
|
||||
|
||||
#endif // RENAMINGUTILITY_RENAMINGENGINE_H
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef SCRIPTDEFS_H
|
||||
#define SCRIPTDEFS_H
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
#if TAGEDITOR_USE_JSENGINE
|
||||
# define TAGEDITOR_JS_ENGINE QJSEngine
|
||||
# define TAGEDITOR_JS_VALUE QJSValue
|
||||
# define TAGEDITOR_JS_READONLY
|
||||
# define TAGEDITOR_JS_UNDELETABLE
|
||||
# define TAGEDITOR_JS_QOBJECT(engine, obj) engine.newQObject(obj)
|
||||
# define TAGEDITOR_JS_INT(value) value.toInt()
|
||||
# define TAGEDITOR_JS_IS_VALID_PROG(program) (!program.isError() && program.isCallable())
|
||||
QT_FORWARD_DECLARE_CLASS(QJSValue)
|
||||
QT_FORWARD_DECLARE_CLASS(QJSEngine)
|
||||
#else
|
||||
# define TAGEDITOR_JS_ENGINE QScriptEngine
|
||||
# define TAGEDITOR_JS_VALUE QScriptValue
|
||||
# define TAGEDITOR_JS_READONLY ,QScriptValue::ReadOnly
|
||||
# define TAGEDITOR_JS_UNDELETABLE ,QScriptValue::Undeletable
|
||||
# define TAGEDITOR_JS_QOBJECT(engine, obj) engine.newQObject(obj, QScriptEngine::ScriptOwnership)
|
||||
# define TAGEDITOR_JS_INT(value) value.toInt32()
|
||||
# define TAGEDITOR_JS_IS_VALID_PROG(program) (!program.isError() && program.isFunction())
|
||||
QT_FORWARD_DECLARE_CLASS(QScriptValue)
|
||||
QT_FORWARD_DECLARE_CLASS(QScriptEngine)
|
||||
#endif
|
||||
|
||||
#endif // SCRIPTDEFS_H
|
|
@ -1,200 +0,0 @@
|
|||
#include "./scriptfunctions.h"
|
||||
|
||||
#include "../misc/utility.h"
|
||||
|
||||
#include <tagparser/mediafileinfo.h>
|
||||
#include <tagparser/tag.h>
|
||||
#include <tagparser/tagvalue.h>
|
||||
#include <tagparser/exceptions.h>
|
||||
|
||||
#include <c++utilities/conversion/conversionexception.h>
|
||||
|
||||
#include <QDir>
|
||||
#include <QScriptEngine>
|
||||
#include <QScriptContext>
|
||||
#include <QScriptValue>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace ConversionUtilities;
|
||||
using namespace Utility;
|
||||
using namespace Media;
|
||||
using namespace std;
|
||||
|
||||
namespace RenamingUtility {
|
||||
|
||||
/*
|
||||
TRANSLATOR RenamingUtility::ScriptFunctions
|
||||
Necessary for lupdate.
|
||||
*/
|
||||
|
||||
QScriptValue &operator <<(QScriptValue ¬ificationsObject, const StatusProvider &statusProvider)
|
||||
{
|
||||
quint32 counter = 0;
|
||||
for(const auto ¬ification : statusProvider.notifications()) {
|
||||
QScriptValue val;
|
||||
val.setProperty("msg", QString::fromLocal8Bit(notification.message().data()), QScriptValue::ReadOnly);
|
||||
val.setProperty("critical", notification.type() == NotificationType::Critical, QScriptValue::ReadOnly);
|
||||
notificationsObject.setProperty(counter, val);
|
||||
++counter;
|
||||
}
|
||||
return notificationsObject;
|
||||
}
|
||||
|
||||
QScriptValue &operator <<(QScriptValue &tagObject, const Tag &tag)
|
||||
{
|
||||
// text fields
|
||||
tagObject.setProperty("title", tagValueToQString(tag.value(KnownField::Title)), QScriptValue::ReadOnly);
|
||||
tagObject.setProperty("artist", tagValueToQString(tag.value(KnownField::Artist)), QScriptValue::ReadOnly);
|
||||
tagObject.setProperty("album", tagValueToQString(tag.value(KnownField::Album)), QScriptValue::ReadOnly);
|
||||
tagObject.setProperty("year", tagValueToQString(tag.value(KnownField::Year)), QScriptValue::ReadOnly);
|
||||
tagObject.setProperty("comment", tagValueToQString(tag.value(KnownField::Comment)), QScriptValue::ReadOnly);
|
||||
tagObject.setProperty("genre", tagValueToQString(tag.value(KnownField::Genre)), QScriptValue::ReadOnly);
|
||||
tagObject.setProperty("encoder", tagValueToQString(tag.value(KnownField::Encoder)), QScriptValue::ReadOnly);
|
||||
tagObject.setProperty("language", tagValueToQString(tag.value(KnownField::Language)), QScriptValue::ReadOnly);
|
||||
tagObject.setProperty("descriptions", tagValueToQString(tag.value(KnownField::Description)), QScriptValue::ReadOnly);
|
||||
// numeric fields
|
||||
try {
|
||||
tagObject.setProperty("partNumber", tag.value(KnownField::PartNumber).toInteger(), QScriptValue::ReadOnly);
|
||||
} catch(ConversionException &) {}
|
||||
try {
|
||||
tagObject.setProperty("totalParts", tag.value(KnownField::TotalParts).toInteger(), QScriptValue::ReadOnly);
|
||||
} catch(ConversionException &) {}
|
||||
PositionInSet pos;
|
||||
try {
|
||||
pos = tag.value(KnownField::TrackPosition).toPositionIntSet();
|
||||
} catch(ConversionException &) {}
|
||||
tagObject.setProperty("trackPos", pos.position(), QScriptValue::ReadOnly);
|
||||
tagObject.setProperty("trackTotal", pos.total(), QScriptValue::ReadOnly);
|
||||
pos = PositionInSet();
|
||||
try {
|
||||
pos = tag.value(KnownField::DiskPosition).toPositionIntSet();
|
||||
} catch(ConversionException &) {}
|
||||
tagObject.setProperty("diskPos", pos.position(), QScriptValue::ReadOnly);
|
||||
tagObject.setProperty("diskTotal", pos.total(), QScriptValue::ReadOnly);
|
||||
// notifications
|
||||
tagObject.setProperty("hasCriticalNotifications", tag.hasCriticalNotifications(), QScriptValue::ReadOnly);
|
||||
return tagObject;
|
||||
}
|
||||
|
||||
QScriptValue ScriptFunctions::parseFileInfo(QScriptContext *context, QScriptEngine *engine)
|
||||
{
|
||||
if(context->argumentCount() != 1 && !context->argument(0).isString()) {
|
||||
return QScriptValue();
|
||||
}
|
||||
auto fileName = context->argument(0).toString();
|
||||
MediaFileInfo fileInfo(fileName.toLocal8Bit().data());
|
||||
|
||||
QScriptValue fileInfoObject = engine->newObject();
|
||||
fileInfoObject.setProperty("currentName", QString::fromLocal8Bit(fileInfo.fileName(false).data()));
|
||||
fileInfoObject.setProperty("currentBaseName", QString::fromLocal8Bit(fileInfo.fileName(true).data()));
|
||||
QString suffix = QString::fromLocal8Bit(fileInfo.extension().data());
|
||||
if(suffix.startsWith('.')) {
|
||||
suffix.remove(0, 1);
|
||||
}
|
||||
fileInfoObject.setProperty("currentSuffix", suffix, QScriptValue::ReadOnly);
|
||||
bool critical = false;
|
||||
try {
|
||||
fileInfo.parseEverything();
|
||||
} catch(Failure &) {
|
||||
// parsing notifications will be addded anyways
|
||||
critical = true;
|
||||
} catch(ios_base::failure &) {
|
||||
critical = true;
|
||||
}
|
||||
|
||||
QScriptValue mainNotificationObject = engine->newArray(fileInfo.notifications().size());
|
||||
mainNotificationObject << fileInfo;
|
||||
critical |= fileInfo.hasCriticalNotifications();
|
||||
fileInfoObject.setProperty("hasCriticalNotifications", critical);
|
||||
fileInfoObject.setProperty("notifications", mainNotificationObject);
|
||||
|
||||
fileInfoObject.setProperty("mimeType", QString::fromLocal8Bit(fileInfo.mimeType()), QScriptValue::ReadOnly);
|
||||
fileInfoObject.setProperty("suitableSuffix", QString::fromLocal8Bit(fileInfo.containerFormatAbbreviation()), QScriptValue::ReadOnly);
|
||||
|
||||
vector<Tag *> tags;
|
||||
fileInfo.tags(tags);
|
||||
QScriptValue combinedTagObject = engine->newObject();
|
||||
QScriptValue combinedTagNotifications = engine->newArray();
|
||||
QScriptValue tagsObject = engine->newArray(tags.size());
|
||||
uint32 tagIndex = 0;
|
||||
|
||||
for(auto tagIterator = tags.cbegin(), end = tags.cend(); tagIterator != end; ++tagIterator, ++tagIndex) {
|
||||
const Tag &tag = **tagIterator;
|
||||
QScriptValue tagObject = engine->newObject();
|
||||
combinedTagObject << tag;
|
||||
combinedTagNotifications << tag;
|
||||
tagObject << tag;
|
||||
QScriptValue tagNotificationsObject = engine->newArray(tag.notifications().size());
|
||||
tagNotificationsObject << tag;
|
||||
tagObject.setProperty("notifications", tagNotificationsObject, QScriptValue::ReadOnly);
|
||||
tagsObject.setProperty(tagIndex, tagObject, QScriptValue::ReadOnly);
|
||||
}
|
||||
combinedTagObject.setProperty("notifications", combinedTagNotifications, QScriptValue::ReadOnly);
|
||||
fileInfoObject.setProperty("tag", combinedTagObject, QScriptValue::ReadOnly);
|
||||
fileInfoObject.setProperty("tags", tagsObject, QScriptValue::ReadOnly);
|
||||
return fileInfoObject;
|
||||
}
|
||||
|
||||
QScriptValue ScriptFunctions::parseFileName(QScriptContext *context, QScriptEngine *engine)
|
||||
{
|
||||
if(context->argumentCount() != 1 && !context->argument(0).isString()) {
|
||||
return QScriptValue();
|
||||
}
|
||||
QString fileName = context->argument(0).toString();
|
||||
QString title;
|
||||
int trackNumber = 0;
|
||||
Utility::parseFileName(fileName, title, trackNumber);
|
||||
QScriptValue result = engine->newObject();
|
||||
result.setProperty("title", QScriptValue(title), QScriptValue::ReadOnly);
|
||||
result.setProperty("trackPos", QScriptValue(trackNumber), QScriptValue::ReadOnly);
|
||||
return result;
|
||||
}
|
||||
|
||||
QScriptValue ScriptFunctions::allFiles(QScriptContext *context, QScriptEngine *engine)
|
||||
{
|
||||
if(context->argumentCount() != 1 && !context->argument(0).isString()) {
|
||||
return QScriptValue();
|
||||
}
|
||||
QString dirName = context->argument(0).toString();
|
||||
QDir dir(dirName);
|
||||
if(dir.exists()) {
|
||||
QStringList files = dir.entryList(QDir::Files);
|
||||
QScriptValue entriesObj = engine->newArray(files.length());
|
||||
quint32 counter = 0;
|
||||
foreach(const QString &file, files) {
|
||||
entriesObj.setProperty(counter, file, QScriptValue::ReadOnly);
|
||||
++counter;
|
||||
}
|
||||
return entriesObj;
|
||||
} else {
|
||||
return QScriptValue();
|
||||
}
|
||||
}
|
||||
|
||||
QScriptValue ScriptFunctions::firstFile(QScriptContext *context, QScriptEngine *engine)
|
||||
{
|
||||
if(context->argumentCount() != 1 && !context->argument(0).isString()) {
|
||||
return QScriptValue();
|
||||
}
|
||||
QString dirName = context->argument(0).toString();
|
||||
QDir dir(dirName);
|
||||
if(dir.exists()) {
|
||||
QStringList files = dir.entryList(QDir::Files);
|
||||
if(files.length() > 0) {
|
||||
return engine->newVariant(files.first());
|
||||
}
|
||||
}
|
||||
return QScriptValue();
|
||||
}
|
||||
|
||||
QScriptValue ScriptFunctions::writeLog(QScriptContext *context, QScriptEngine *)
|
||||
{
|
||||
if(context->argumentCount() != 1 && !context->argument(0).isString()) {
|
||||
return QScriptValue();
|
||||
}
|
||||
cout << context->argument(0).toString().toStdString() << endl;
|
||||
return QScriptValue();
|
||||
}
|
||||
|
||||
} // namespace RenamingUtility
|
|
@ -1,26 +0,0 @@
|
|||
#ifndef RENAMINGUTILITY_SCRIPTFUNCTIONS_H
|
||||
#define RENAMINGUTILITY_SCRIPTFUNCTIONS_H
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QScriptValue;
|
||||
class QScriptContext;
|
||||
class QScriptEngine;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace RenamingUtility {
|
||||
|
||||
class ScriptFunctions
|
||||
{
|
||||
public:
|
||||
static QScriptValue parseFileInfo(QScriptContext *context, QScriptEngine *engine);
|
||||
static QScriptValue parseFileName(QScriptContext *context, QScriptEngine *engine);
|
||||
static QScriptValue allFiles(QScriptContext *context, QScriptEngine *engine);
|
||||
static QScriptValue firstFile(QScriptContext *context, QScriptEngine *engine);
|
||||
static QScriptValue writeLog(QScriptContext *context, QScriptEngine *);
|
||||
};
|
||||
|
||||
} // namespace RenamingUtility
|
||||
|
||||
#endif // RENAMINGUTILITY_SCRIPTFUNCTIONS_H
|
|
@ -0,0 +1,250 @@
|
|||
#include "./tageditorobject.h"
|
||||
#include "./filesystemitem.h"
|
||||
|
||||
#include "../misc/utility.h"
|
||||
|
||||
#include <tagparser/mediafileinfo.h>
|
||||
#include <tagparser/tag.h>
|
||||
#include <tagparser/tagvalue.h>
|
||||
#include <tagparser/exceptions.h>
|
||||
|
||||
#include <c++utilities/conversion/conversionexception.h>
|
||||
|
||||
#include <QDir>
|
||||
|
||||
#ifdef TAGEDITOR_USE_JSENGINE
|
||||
# include <QJSEngine>
|
||||
# include <QJSValue>
|
||||
#else
|
||||
# include <QScriptEngine>
|
||||
# include <QScriptValue>
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using namespace ConversionUtilities;
|
||||
using namespace Utility;
|
||||
using namespace Media;
|
||||
using namespace std;
|
||||
|
||||
namespace RenamingUtility {
|
||||
|
||||
TAGEDITOR_JS_VALUE &operator <<(TAGEDITOR_JS_VALUE ¬ificationsObject, const StatusProvider &statusProvider)
|
||||
{
|
||||
quint32 counter = 0;
|
||||
for(const auto ¬ification : statusProvider.notifications()) {
|
||||
TAGEDITOR_JS_VALUE val;
|
||||
val.setProperty("msg", QString::fromLocal8Bit(notification.message().data()) TAGEDITOR_JS_READONLY);
|
||||
val.setProperty("critical", notification.type() == NotificationType::Critical TAGEDITOR_JS_READONLY);
|
||||
notificationsObject.setProperty(counter, val);
|
||||
++counter;
|
||||
}
|
||||
return notificationsObject;
|
||||
}
|
||||
|
||||
TAGEDITOR_JS_VALUE &operator <<(TAGEDITOR_JS_VALUE &tagObject, const Tag &tag)
|
||||
{
|
||||
// text fields
|
||||
tagObject.setProperty("title", tagValueToQString(tag.value(KnownField::Title)) TAGEDITOR_JS_READONLY);
|
||||
tagObject.setProperty("artist", tagValueToQString(tag.value(KnownField::Artist)) TAGEDITOR_JS_READONLY);
|
||||
tagObject.setProperty("album", tagValueToQString(tag.value(KnownField::Album)) TAGEDITOR_JS_READONLY);
|
||||
tagObject.setProperty("year", tagValueToQString(tag.value(KnownField::Year)) TAGEDITOR_JS_READONLY);
|
||||
tagObject.setProperty("comment", tagValueToQString(tag.value(KnownField::Comment)) TAGEDITOR_JS_READONLY);
|
||||
tagObject.setProperty("genre", tagValueToQString(tag.value(KnownField::Genre)) TAGEDITOR_JS_READONLY);
|
||||
tagObject.setProperty("encoder", tagValueToQString(tag.value(KnownField::Encoder)) TAGEDITOR_JS_READONLY);
|
||||
tagObject.setProperty("language", tagValueToQString(tag.value(KnownField::Language)) TAGEDITOR_JS_READONLY);
|
||||
tagObject.setProperty("descriptions", tagValueToQString(tag.value(KnownField::Description)) TAGEDITOR_JS_READONLY);
|
||||
// numeric fields
|
||||
try {
|
||||
tagObject.setProperty("partNumber", tag.value(KnownField::PartNumber).toInteger() TAGEDITOR_JS_READONLY);
|
||||
} catch(ConversionException &) {}
|
||||
try {
|
||||
tagObject.setProperty("totalParts", tag.value(KnownField::TotalParts).toInteger() TAGEDITOR_JS_READONLY);
|
||||
} catch(ConversionException &) {}
|
||||
PositionInSet pos;
|
||||
try {
|
||||
pos = tag.value(KnownField::TrackPosition).toPositionIntSet();
|
||||
} catch(ConversionException &) {}
|
||||
tagObject.setProperty("trackPos", pos.position() TAGEDITOR_JS_READONLY);
|
||||
tagObject.setProperty("trackTotal", pos.total() TAGEDITOR_JS_READONLY);
|
||||
pos = PositionInSet();
|
||||
try {
|
||||
pos = tag.value(KnownField::DiskPosition).toPositionIntSet();
|
||||
} catch(ConversionException &) {}
|
||||
tagObject.setProperty("diskPos", pos.position() TAGEDITOR_JS_READONLY);
|
||||
tagObject.setProperty("diskTotal", pos.total() TAGEDITOR_JS_READONLY);
|
||||
// notifications
|
||||
tagObject.setProperty("hasCriticalNotifications", tag.hasCriticalNotifications() TAGEDITOR_JS_READONLY);
|
||||
return tagObject;
|
||||
}
|
||||
|
||||
TagEditorObject::TagEditorObject(TAGEDITOR_JS_ENGINE *engine) :
|
||||
m_engine(engine),
|
||||
m_currentType(ItemType::Dir),
|
||||
m_action(ActionType::None)
|
||||
{}
|
||||
|
||||
void TagEditorObject::setFileInfo(const QFileInfo &file, FileSystemItem *item)
|
||||
{
|
||||
m_currentPath = file.absoluteFilePath();
|
||||
m_currentName = file.fileName();
|
||||
m_currentRelativeDirectory = item->relativeDir();
|
||||
m_currentType = item->type();
|
||||
m_action = ActionType::None;
|
||||
m_newName.clear();
|
||||
m_newRelativeDirectory.clear();
|
||||
}
|
||||
|
||||
const QString &TagEditorObject::currentPath() const
|
||||
{
|
||||
return m_currentPath;
|
||||
}
|
||||
|
||||
const QString &TagEditorObject::currentName() const
|
||||
{
|
||||
return m_currentName;
|
||||
}
|
||||
|
||||
const QString &TagEditorObject::currentRelativeDirectory() const
|
||||
{
|
||||
return m_currentRelativeDirectory;
|
||||
}
|
||||
|
||||
bool TagEditorObject::isDir() const
|
||||
{
|
||||
return m_currentType == ItemType::Dir;
|
||||
}
|
||||
|
||||
bool TagEditorObject::isFile() const
|
||||
{
|
||||
return m_currentType == ItemType::File;
|
||||
}
|
||||
|
||||
const QString &TagEditorObject::newName() const
|
||||
{
|
||||
return m_newName;
|
||||
}
|
||||
|
||||
const QString &TagEditorObject::newRelativeDirectory() const
|
||||
{
|
||||
return m_newRelativeDirectory;
|
||||
}
|
||||
|
||||
TAGEDITOR_JS_VALUE TagEditorObject::parseFileInfo(const QString &fileName)
|
||||
{
|
||||
MediaFileInfo fileInfo(fileName.toLocal8Bit().data());
|
||||
|
||||
auto fileInfoObject = m_engine->newObject();
|
||||
fileInfoObject.setProperty(QStringLiteral("currentName"), QString::fromLocal8Bit(fileInfo.fileName(false).data()));
|
||||
fileInfoObject.setProperty(QStringLiteral("currentBaseName"), QString::fromLocal8Bit(fileInfo.fileName(true).data()));
|
||||
QString suffix = QString::fromLocal8Bit(fileInfo.extension().data());
|
||||
if(suffix.startsWith('.')) {
|
||||
suffix.remove(0, 1);
|
||||
}
|
||||
fileInfoObject.setProperty(QStringLiteral("currentSuffix"), suffix TAGEDITOR_JS_READONLY);
|
||||
bool critical = false;
|
||||
try {
|
||||
fileInfo.parseEverything();
|
||||
} catch(Failure &) {
|
||||
// parsing notifications will be addded anyways
|
||||
critical = true;
|
||||
} catch(ios_base::failure &) {
|
||||
critical = true;
|
||||
}
|
||||
|
||||
auto mainNotificationObject = m_engine->newArray(fileInfo.notifications().size());
|
||||
mainNotificationObject << fileInfo;
|
||||
critical |= fileInfo.hasCriticalNotifications();
|
||||
fileInfoObject.setProperty(QStringLiteral("hasCriticalNotifications"), critical);
|
||||
fileInfoObject.setProperty(QStringLiteral("notifications"), mainNotificationObject);
|
||||
|
||||
fileInfoObject.setProperty(QStringLiteral("mimeType"), QString::fromLocal8Bit(fileInfo.mimeType()) TAGEDITOR_JS_READONLY);
|
||||
fileInfoObject.setProperty(QStringLiteral("suitableSuffix"), QString::fromLocal8Bit(fileInfo.containerFormatAbbreviation()) TAGEDITOR_JS_READONLY);
|
||||
|
||||
vector<Tag *> tags;
|
||||
fileInfo.tags(tags);
|
||||
auto combinedTagObject = m_engine->newObject();
|
||||
auto combinedTagNotifications = m_engine->newArray();
|
||||
auto tagsObject = m_engine->newArray(tags.size());
|
||||
uint32 tagIndex = 0;
|
||||
|
||||
for(auto tagIterator = tags.cbegin(), end = tags.cend(); tagIterator != end; ++tagIterator, ++tagIndex) {
|
||||
const Tag &tag = **tagIterator;
|
||||
auto tagObject = m_engine->newObject();
|
||||
combinedTagObject << tag;
|
||||
combinedTagNotifications << tag;
|
||||
tagObject << tag;
|
||||
auto tagNotificationsObject = m_engine->newArray(tag.notifications().size());
|
||||
tagNotificationsObject << tag;
|
||||
tagObject.setProperty(QStringLiteral("notifications"), tagNotificationsObject TAGEDITOR_JS_READONLY);
|
||||
tagsObject.setProperty(tagIndex, tagObject TAGEDITOR_JS_READONLY);
|
||||
}
|
||||
combinedTagObject.setProperty(QStringLiteral("notifications"), combinedTagNotifications TAGEDITOR_JS_READONLY);
|
||||
fileInfoObject.setProperty(QStringLiteral("tag"), combinedTagObject TAGEDITOR_JS_READONLY);
|
||||
fileInfoObject.setProperty(QStringLiteral("tags"), tagsObject TAGEDITOR_JS_READONLY);
|
||||
return fileInfoObject;
|
||||
}
|
||||
|
||||
TAGEDITOR_JS_VALUE TagEditorObject::parseFileName(const QString &fileName)
|
||||
{
|
||||
QString title;
|
||||
int trackNumber = 0;
|
||||
Utility::parseFileName(fileName, title, trackNumber);
|
||||
auto result = m_engine->newObject();
|
||||
result.setProperty(QStringLiteral("title"), TAGEDITOR_JS_VALUE(title) TAGEDITOR_JS_READONLY);
|
||||
result.setProperty(QStringLiteral("trackPos"), TAGEDITOR_JS_VALUE(trackNumber) TAGEDITOR_JS_READONLY);
|
||||
return result;
|
||||
}
|
||||
|
||||
TAGEDITOR_JS_VALUE TagEditorObject::allFiles(const QString &dirName)
|
||||
{
|
||||
QDir dir(dirName);
|
||||
if(dir.exists()) {
|
||||
QStringList files = dir.entryList(QDir::Files);
|
||||
auto entriesObj = m_engine->newArray(files.length());
|
||||
quint32 counter = 0;
|
||||
foreach(const QString &file, files) {
|
||||
entriesObj.setProperty(counter, file TAGEDITOR_JS_READONLY);
|
||||
++counter;
|
||||
}
|
||||
return entriesObj;
|
||||
} else {
|
||||
return TAGEDITOR_JS_VALUE();
|
||||
}
|
||||
}
|
||||
|
||||
TAGEDITOR_JS_VALUE TagEditorObject::firstFile(const QString &dirName)
|
||||
{
|
||||
QDir dir(dirName);
|
||||
if(dir.exists()) {
|
||||
QStringList files = dir.entryList(QDir::Files);
|
||||
if(!files.empty()) {
|
||||
return TAGEDITOR_JS_VALUE(files.first());
|
||||
}
|
||||
}
|
||||
return TAGEDITOR_JS_VALUE();
|
||||
}
|
||||
|
||||
void TagEditorObject::writeLog(const QString &message)
|
||||
{
|
||||
cout << message.toStdString() << endl;
|
||||
}
|
||||
|
||||
void TagEditorObject::rename(const QString &newName)
|
||||
{
|
||||
m_newName = newName;
|
||||
m_action = ActionType::Rename;
|
||||
}
|
||||
|
||||
void TagEditorObject::move(const QString &newRelativeDirectory)
|
||||
{
|
||||
m_newRelativeDirectory = newRelativeDirectory;
|
||||
m_action = ActionType::Rename;
|
||||
}
|
||||
|
||||
void TagEditorObject::skip()
|
||||
{
|
||||
m_action = ActionType::Skip;
|
||||
}
|
||||
|
||||
} // namespace RenamingUtility
|
|
@ -0,0 +1,75 @@
|
|||
#ifndef RENAMINGUTILITY_SCRIPTFUNCTIONS_H
|
||||
#define RENAMINGUTILITY_SCRIPTFUNCTIONS_H
|
||||
|
||||
#include "./scriptdefs.h"
|
||||
|
||||
#include <QObject>
|
||||
#ifdef TAGEDITOR_USE_JSENGINE
|
||||
# include <QJSValue>
|
||||
#else
|
||||
# include <QScriptValue>
|
||||
#endif
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QFileInfo)
|
||||
|
||||
namespace RenamingUtility {
|
||||
|
||||
class FileSystemItem;
|
||||
enum class ItemType;
|
||||
enum class ActionType;
|
||||
|
||||
class TagEditorObject : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString currentPath READ currentPath)
|
||||
Q_PROPERTY(QString currentName READ currentName)
|
||||
Q_PROPERTY(QString currentRelativeDirectory READ currentRelativeDirectory)
|
||||
Q_PROPERTY(bool isDir READ isDir)
|
||||
Q_PROPERTY(bool isFile READ isFile)
|
||||
Q_PROPERTY(QString newName READ newName WRITE rename)
|
||||
Q_PROPERTY(QString newRelativeDirectory READ newRelativeDirectory WRITE move)
|
||||
|
||||
public:
|
||||
TagEditorObject(TAGEDITOR_JS_ENGINE *engine);
|
||||
|
||||
ActionType action() const;
|
||||
void setFileInfo(const QFileInfo &file, FileSystemItem *item);
|
||||
|
||||
const QString ¤tPath() const;
|
||||
const QString ¤tName() const;
|
||||
const QString ¤tRelativeDirectory() const;
|
||||
bool isDir() const;
|
||||
bool isFile() const;
|
||||
const QString &newName() const;
|
||||
const QString &newRelativeDirectory() const;
|
||||
|
||||
public slots:
|
||||
TAGEDITOR_JS_VALUE parseFileInfo(const QString &fileName);
|
||||
TAGEDITOR_JS_VALUE parseFileName(const QString &fileName);
|
||||
TAGEDITOR_JS_VALUE allFiles(const QString &dirName);
|
||||
TAGEDITOR_JS_VALUE firstFile(const QString &dirName);
|
||||
void writeLog(const QString &message);
|
||||
void rename(const QString &newName);
|
||||
void move(const QString &newRelativeDirectory);
|
||||
void skip();
|
||||
|
||||
|
||||
private:
|
||||
TAGEDITOR_JS_ENGINE *m_engine;
|
||||
QString m_currentPath;
|
||||
QString m_currentName;
|
||||
QString m_currentRelativeDirectory;
|
||||
ItemType m_currentType;
|
||||
ActionType m_action;
|
||||
QString m_newName;
|
||||
QString m_newRelativeDirectory;
|
||||
};
|
||||
|
||||
inline ActionType TagEditorObject::action() const
|
||||
{
|
||||
return m_action;
|
||||
}
|
||||
|
||||
} // namespace RenamingUtility
|
||||
|
||||
#endif // RENAMINGUTILITY_SCRIPTFUNCTIONS_H
|
|
@ -21,27 +21,27 @@ var distDir = false;
|
|||
// string used for "miscellaneous" category
|
||||
var misc = "misc";
|
||||
|
||||
// define helper functions
|
||||
// define some helper functions
|
||||
|
||||
/*!
|
||||
* \brief Returns whether the specified \a value is not undefined
|
||||
and not an empty string.
|
||||
* Returns whether the specified \a value is not undefined
|
||||
* and not an empty string.
|
||||
*/
|
||||
function notEmpty(value) {
|
||||
return value !== undefined && value !== "";
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns whether the specified \a value is not undefined
|
||||
and not zero.
|
||||
* Returns whether the specified \a value is not undefined
|
||||
* and not zero.
|
||||
*/
|
||||
function notNull(value) {
|
||||
return value !== undefined && value !== 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the string representation of \a pos using at least as
|
||||
many digits as \a total has.
|
||||
* Returns the string representation of \a pos using at least as
|
||||
* many digits as \a total has.
|
||||
*/
|
||||
function appropriateDigitCount(pos, total) {
|
||||
var res = pos + "";
|
||||
|
@ -53,8 +53,8 @@ function appropriateDigitCount(pos, total) {
|
|||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns a copy of the specified \a name with characters that might be
|
||||
avoided in file names striped out.
|
||||
* Returns a copy of the specified \a name with characters that might be
|
||||
* avoided in file names striped out.
|
||||
*/
|
||||
function validFileName(name) {
|
||||
if(name !== undefined) {
|
||||
|
@ -65,8 +65,8 @@ function validFileName(name) {
|
|||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns a copy of the specified \a name with characters that might be
|
||||
avoided in directory names striped out.
|
||||
* Returns a copy of the specified \a name with characters that might be
|
||||
* avoided in directory names striped out.
|
||||
*/
|
||||
function validDirectoryName(name) {
|
||||
if(name !== undefined) {
|
||||
|
@ -79,21 +79,21 @@ function validDirectoryName(name) {
|
|||
// the actual script
|
||||
|
||||
// check whether we have to deal with a file or a directory
|
||||
if(isFile) {
|
||||
if(tageditor.isFile) {
|
||||
// parse file using the built-in parseFileInfo function
|
||||
var fileInfo = parseFileInfo(currentPath);
|
||||
var fileInfo = tageditor.parseFileInfo(tageditor.currentPath);
|
||||
var tag = fileInfo.tag; // get the tag information
|
||||
// read title and track number from the file name using the built-in parseFileName function
|
||||
var infoFromFileName = parseFileName(fileInfo.currentBaseName);
|
||||
var infoFromFileName = tageditor.parseFileName(fileInfo.currentBaseName);
|
||||
// read the suffix from the file info object to filter backup and temporary files
|
||||
if(fileInfo.currentName === "desktop.ini") {
|
||||
action = actionType.skip; // skip these files
|
||||
tageditor.skip(); // skip these files
|
||||
} else if(fileInfo.currentSuffix === "bak") {
|
||||
// filter backup files by setting newRelativeDirectory to put them in a separate directory
|
||||
newRelativeDirectory = "backups";
|
||||
// filter backup by putting them in a separate directory
|
||||
tageditor.move("backups");
|
||||
} else if(fileInfo.currentSuffix === "tmp") {
|
||||
// filter temporary files in the same way as backup files
|
||||
newRelativeDirectory = "temp";
|
||||
tageditor.move("temp");
|
||||
} else {
|
||||
// define an array for the fields; will be joined later
|
||||
var fields = [];
|
||||
|
@ -135,7 +135,7 @@ if(isFile) {
|
|||
fields.push(appropriateDigitCount(infoFromFileName.trackPos, 10));
|
||||
}
|
||||
// join the first part of the new name
|
||||
newName = fields.join(separator);
|
||||
var newName = fields.join(separator);
|
||||
// get the title
|
||||
var title = validFileName(tag.title);
|
||||
// append the title (if configured and present)
|
||||
|
@ -163,6 +163,8 @@ if(isFile) {
|
|||
if(notEmpty(suffix)) {
|
||||
newName = newName.concat(".", suffix);
|
||||
}
|
||||
// apply new name
|
||||
tageditor.rename(newName);
|
||||
// set the distribution directory
|
||||
if(distDir) {
|
||||
var path = [distDir];
|
||||
|
@ -185,13 +187,11 @@ if(isFile) {
|
|||
if(tag.diskTotal >= 2) {
|
||||
path.push("Disk " + appropriateDigitCount(tag.diskPos, tag.diskTotal));
|
||||
}
|
||||
newRelativeDirectory = path.join("/");
|
||||
// apply new relative directory
|
||||
tageditor.move(path.join("/"));
|
||||
}
|
||||
}
|
||||
// set the action to "actionType.renaming"
|
||||
// (this is the default action, actually there is no need to set it explicitly)
|
||||
action = actionType.rename;
|
||||
} else if(isDir) {
|
||||
// skip directories in this example script by setting the action to "actionType.skip"
|
||||
action = actionType.skip;
|
||||
} else if(tageditor.isDir) {
|
||||
// skip directories in this example script
|
||||
tageditor.skip();
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ VERSION = 1.3.0
|
|||
|
||||
# basic configuration: application
|
||||
TEMPLATE = app
|
||||
QT += core gui widgets script
|
||||
QT += core gui widgets
|
||||
# use webkitwidgets if available; otherwise use webenginewidgets
|
||||
!forcewebengine:qtHaveModule(webkitwidgets) {
|
||||
QT += webkitwidgets
|
||||
|
@ -23,9 +23,17 @@ QT += core gui widgets script
|
|||
QT += webenginewidgets
|
||||
DEFINES += TAGEDITOR_USE_WEBENGINE
|
||||
}
|
||||
# use script if available; otherwise use qml
|
||||
!forcejsengine:qtHaveModule(script) {
|
||||
QT += script
|
||||
} else {
|
||||
QT += qml
|
||||
DEFINES += TAGEDITOR_USE_JSENGINE
|
||||
}
|
||||
|
||||
# add project files
|
||||
HEADERS += application/main.h \
|
||||
HEADERS += \
|
||||
application/main.h \
|
||||
application/knownfieldmodel.h \
|
||||
application/settings.h \
|
||||
gui/filefilterproxymodel.h \
|
||||
|
@ -44,7 +52,8 @@ HEADERS += application/main.h \
|
|||
renamingutility/filesystemitemmodel.h \
|
||||
renamingutility/filteredfilesystemitemmodel.h \
|
||||
renamingutility/renamingengine.h \
|
||||
renamingutility/scriptfunctions.h \
|
||||
renamingutility/scriptdefs.h \
|
||||
renamingutility/tageditorobject.h \
|
||||
misc/htmlinfo.h \
|
||||
gui/previousvaluehandling.h \
|
||||
gui/initiate.h \
|
||||
|
@ -55,7 +64,8 @@ HEADERS += application/main.h \
|
|||
gui/attachmentsedit.h \
|
||||
gui/codeedit.h
|
||||
|
||||
SOURCES += application/main.cpp \
|
||||
SOURCES += \
|
||||
application/main.cpp \
|
||||
application/knownfieldmodel.cpp \
|
||||
application/settings.cpp \
|
||||
gui/filefilterproxymodel.cpp \
|
||||
|
@ -74,9 +84,8 @@ SOURCES += application/main.cpp \
|
|||
renamingutility/filesystemitemmodel.cpp \
|
||||
renamingutility/filteredfilesystemitemmodel.cpp \
|
||||
renamingutility/renamingengine.cpp \
|
||||
renamingutility/scriptfunctions.cpp \
|
||||
renamingutility/tageditorobject.cpp \
|
||||
misc/htmlinfo.cpp \
|
||||
gui/previousvaluehandling.cpp \
|
||||
gui/initiate.cpp \
|
||||
cli/mainfeatures.cpp \
|
||||
misc/utility.cpp \
|
||||
|
|
Loading…
Reference in New Issue