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:
Martchus 2016-01-09 02:56:56 +01:00
parent 10bfa8aeea
commit 1c4d577264
29 changed files with 489 additions and 426 deletions

View File

@ -60,7 +60,8 @@ set(WIDGETS_HEADER_FILES
renamingutility/filesystemitemmodel.h renamingutility/filesystemitemmodel.h
renamingutility/filteredfilesystemitemmodel.h renamingutility/filteredfilesystemitemmodel.h
renamingutility/renamingengine.h renamingutility/renamingengine.h
renamingutility/scriptfunctions.h renamingutility/scriptdefs.h
renamingutility/tageditorobject.h
) )
set(WIDGETS_SRC_FILES set(WIDGETS_SRC_FILES
gui/attachmentsedit.cpp gui/attachmentsedit.cpp
@ -77,7 +78,6 @@ set(WIDGETS_SRC_FILES
gui/infowidgetbase.cpp gui/infowidgetbase.cpp
gui/initiate.cpp gui/initiate.cpp
gui/javascripthighlighter.cpp gui/javascripthighlighter.cpp
gui/previousvaluehandling.cpp
gui/renamefilesdialog.cpp gui/renamefilesdialog.cpp
gui/settingsdialog.cpp gui/settingsdialog.cpp
gui/tagedit.cpp gui/tagedit.cpp
@ -86,7 +86,7 @@ set(WIDGETS_SRC_FILES
renamingutility/filesystemitemmodel.cpp renamingutility/filesystemitemmodel.cpp
renamingutility/filteredfilesystemitemmodel.cpp renamingutility/filteredfilesystemitemmodel.cpp
renamingutility/renamingengine.cpp renamingutility/renamingengine.cpp
renamingutility/scriptfunctions.cpp renamingutility/tageditorobject.h
resources/icons.qrc resources/icons.qrc
resources/scripts.qrc resources/scripts.qrc
) )

View File

@ -113,7 +113,10 @@ Here are some Bash examples which illustrate getting and setting tag information
## Build instructions ## Build instructions
The application depends on c++utilities, qtutilities and tagparser and is built in the same way as these libaries. 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. 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. To force usage of webenginewidgets add "CONFIG+=forcewebengine" to the qmake arguments.

View File

@ -4,11 +4,6 @@
namespace QtGui { namespace QtGui {
/*
TRANSLATOR QtGui::FileFilterProxyModel
Necessary for lupdate.
*/
FileFilterProxyModel::FileFilterProxyModel(QObject *parent) : FileFilterProxyModel::FileFilterProxyModel(QObject *parent) :
QSortFilterProxyModel(parent), QSortFilterProxyModel(parent),
m_filterEnabled(true) m_filterEnabled(true)

View File

@ -23,11 +23,6 @@ using namespace Media;
namespace QtGui { namespace QtGui {
/*
TRANSLATOR QtGui::InfoWidgetBase
Necessary for lupdate.
*/
InfoWidgetBase::InfoWidgetBase(QWidget *parent) : InfoWidgetBase::InfoWidgetBase(QWidget *parent) :
QWidget(parent), QWidget(parent),
m_notificationModel(nullptr) m_notificationModel(nullptr)

View File

@ -5,7 +5,7 @@
// include configuration from separate header file when building with CMake // include configuration from separate header file when building with CMake
#ifndef APP_METADATA_AVAIL #ifndef APP_METADATA_AVAIL
#include "resources/config.h" # include "resources/config.h"
#endif #endif
#include <qtutilities/resources/qtconfigarguments.h> #include <qtutilities/resources/qtconfigarguments.h>

View File

@ -64,11 +64,6 @@ using namespace Widgets;
namespace QtGui { namespace QtGui {
/*
TRANSLATOR QtGui::MainWindow
Necessary for lupdate.
*/
/*! /*!
* \brief The LoadingResult enum specifies whether the file could be parsed. * \brief The LoadingResult enum specifies whether the file could be parsed.
*/ */

View File

@ -27,9 +27,6 @@ NotificationLabel::NotificationLabel(QWidget *parent) :
m_updateTimer.setInterval(80); m_updateTimer.setInterval(80);
} }
NotificationLabel::~NotificationLabel()
{}
void NotificationLabel::paintEvent(QPaintEvent *event) void NotificationLabel::paintEvent(QPaintEvent *event)
{ {
QStyle *style = QWidget::style(); QStyle *style = QWidget::style();

View File

@ -33,7 +33,6 @@ class NotificationLabel : public QWidget
Q_PROPERTY(int maxIconSize READ maxIconSize WRITE setMaxIconSize) Q_PROPERTY(int maxIconSize READ maxIconSize WRITE setMaxIconSize)
public: public:
explicit NotificationLabel(QWidget *parent = nullptr); explicit NotificationLabel(QWidget *parent = nullptr);
virtual ~NotificationLabel();
const QString &text() const; const QString &text() const;
NotificationType notificationType() const; NotificationType notificationType() const;

View File

@ -12,11 +12,6 @@ using namespace Media;
namespace QtGui { namespace QtGui {
/*
TRANSLATOR QtGui::NotificationModel
Necessary for lupdate.
*/
NotificationModel::NotificationModel(QObject *parent) : NotificationModel::NotificationModel(QObject *parent) :
QAbstractListModel(parent) QAbstractListModel(parent)
{} {}

View File

@ -15,18 +15,10 @@ using namespace Widgets;
namespace QtGui { namespace QtGui {
/*
TRANSLATOR QtGui::PathLineEdit
Necessary for lupdate.
*/
PathLineEdit::PathLineEdit(QWidget *parent) : PathLineEdit::PathLineEdit(QWidget *parent) :
ClearLineEdit(parent) ClearLineEdit(parent)
{} {}
PathLineEdit::~PathLineEdit()
{}
QAbstractItemModel *PathLineEdit::completionModel() const QAbstractItemModel *PathLineEdit::completionModel() const
{ {
if(QCompleter *c = completer()) { if(QCompleter *c = completer()) {

View File

@ -18,7 +18,6 @@ class PathLineEdit : public Widgets::ClearLineEdit
public: public:
explicit PathLineEdit(QWidget *parent = nullptr); explicit PathLineEdit(QWidget *parent = nullptr);
virtual ~PathLineEdit();
QAbstractItemModel *completionModel() const; QAbstractItemModel *completionModel() const;
void setCompletionModel(QAbstractItemModel *model); void setCompletionModel(QAbstractItemModel *model);

View File

@ -35,11 +35,6 @@ using namespace Media;
namespace QtGui { namespace QtGui {
/*
TRANSLATOR QtGui::PicturePreviewSelection
Necessary for lupdate.
*/
/*! /*!
* \brief Constructs a new PicturePreviewSelection for the specified \a tag and \a field. * \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() PicturePreviewSelection::~PicturePreviewSelection()
{} {}

View File

@ -35,7 +35,7 @@ class PicturePreviewSelection : public QWidget
public: public:
explicit PicturePreviewSelection(Media::Tag *tag = nullptr, Media::KnownField field = Media::KnownField::Invalid, QWidget *parent = nullptr); explicit PicturePreviewSelection(Media::Tag *tag = nullptr, Media::KnownField field = Media::KnownField::Invalid, QWidget *parent = nullptr);
virtual ~PicturePreviewSelection(); ~PicturePreviewSelection();
Media::Tag *tag() const; Media::Tag *tag() const;
Media::KnownField field() const; Media::KnownField field() const;

View File

@ -1,5 +0,0 @@
#include "./previousvaluehandling.h"
namespace QtGui {
}

View File

@ -13,7 +13,6 @@
#include <QMessageBox> #include <QMessageBox>
#include <QFileDialog> #include <QFileDialog>
#include <QDir> #include <QDir>
#include <QScriptEngine>
#include <QItemSelectionModel> #include <QItemSelectionModel>
#include <QMenu> #include <QMenu>
#include <QClipboard> #include <QClipboard>
@ -26,11 +25,6 @@ using namespace RenamingUtility;
namespace QtGui { namespace QtGui {
/*
TRANSLATOR QtGui::RenameFilesDialog
Necessary for lupdate.
*/
RenameFilesDialog::RenameFilesDialog(QWidget *parent) : RenameFilesDialog::RenameFilesDialog(QWidget *parent) :
QDialog(parent), QDialog(parent),
m_ui(new Ui::RenameFilesDialog), m_ui(new Ui::RenameFilesDialog),
@ -44,7 +38,7 @@ RenameFilesDialog::RenameFilesDialog(QWidget *parent) :
setStyleSheet(dialogStyle() + QStringLiteral("QSplitter:handle { background-color: palette(base); }")); setStyleSheet(dialogStyle() + QStringLiteral("QSplitter:handle { background-color: palette(base); }"));
#endif #endif
// setup javascript editor and script file selection // setup javascript editor and script file selection
QFont font("Courier", 10); QFont font(QStringLiteral("Courier"), 10);
font.setFixedPitch(true); font.setFixedPitch(true);
m_ui->javaScriptPlainTextEdit->setFont(font); m_ui->javaScriptPlainTextEdit->setFont(font);
m_highlighter = new JavaScriptHighlighter(m_ui->javaScriptPlainTextEdit->document()); m_highlighter = new JavaScriptHighlighter(m_ui->javaScriptPlainTextEdit->document());
@ -124,7 +118,6 @@ void RenameFilesDialog::startGeneratingPreview()
QDir selectedDir(directory()); QDir selectedDir(directory());
m_ui->notificationLabel->setHidden(false); m_ui->notificationLabel->setHidden(false);
if(selectedDir.exists()) { if(selectedDir.exists()) {
QScriptEngine engine;
QString program; QString program;
if(m_ui->sourceFileStackedWidget->currentIndex() == 0) { if(m_ui->sourceFileStackedWidget->currentIndex() == 0) {
program = m_ui->javaScriptPlainTextEdit->toPlainText(); program = m_ui->javaScriptPlainTextEdit->toPlainText();
@ -143,18 +136,17 @@ void RenameFilesDialog::startGeneratingPreview()
} }
} }
if(!program.isEmpty()) { if(!program.isEmpty()) {
QScriptSyntaxCheckResult res = engine.checkSyntax(program); if(m_engine->setProgram(program)) {
if(res.state() != QScriptSyntaxCheckResult::Error) {
m_ui->notificationLabel->setText(tr("Generating preview ...")); m_ui->notificationLabel->setText(tr("Generating preview ..."));
m_ui->notificationLabel->setNotificationType(NotificationType::Progress); m_ui->notificationLabel->setNotificationType(NotificationType::Progress);
m_ui->abortClosePushButton->setText(tr("Abort")); m_ui->abortClosePushButton->setText(tr("Abort"));
m_ui->generatePreviewPushButton->setHidden(true); m_ui->generatePreviewPushButton->setHidden(true);
m_ui->applyChangingsPushButton->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 { } else {
m_engine->clearPreview(); m_engine->clearPreview();
m_ui->notificationLabel->setText(tr("The script is not valid.\nError in line %1 and column %2:\n %3") m_ui->notificationLabel->setText(tr("The script is not valid.\nError in line %1: %3")
.arg(res.errorLineNumber()).arg(res.errorColumnNumber()).arg(res.errorMessage())); .arg(m_engine->errorLineNumber()).arg(m_engine->errorMessage()));
m_ui->notificationLabel->setNotificationType(NotificationType::Warning); m_ui->notificationLabel->setNotificationType(NotificationType::Warning);
} }
} else { } else {
@ -191,7 +183,7 @@ void RenameFilesDialog::showPreviewProgress(int itemsProcessed, int errorsOccure
m_errorsOccured = errorsOccured; m_errorsOccured = errorsOccured;
QString text = tr("%1 files/directories processed", 0, itemsProcessed).arg(itemsProcessed); QString text = tr("%1 files/directories processed", 0, itemsProcessed).arg(itemsProcessed);
if(m_errorsOccured > 0) { if(m_errorsOccured > 0) {
text.append(QStringLiteral("\n")); text.append(QChar('\n'));
text.append(tr("%1 error(s) occured", 0, errorsOccured).arg(errorsOccured)); text.append(tr("%1 error(s) occured", 0, errorsOccured).arg(errorsOccured));
} }
m_ui->notificationLabel->setText(text); m_ui->notificationLabel->setText(text);

View File

@ -20,11 +20,6 @@ using namespace Media;
namespace QtGui { namespace QtGui {
/*
TRANSLATOR QtGui::TagEdit
Necessary for lupdate.
*/
/*! /*!
* \class QtGui::TagEdit * \class QtGui::TagEdit
* \brief The TagEdit widget allows the user to edit Media::Tag objects. * \brief The TagEdit widget allows the user to edit Media::Tag objects.
@ -55,14 +50,6 @@ TagEdit::TagEdit(QWidget *parent) :
setLayout(mainLayout); setLayout(mainLayout);
} }
/*!
* \brief Destroys the tag edit.
*
* Does not destroy assigned tags.
*/
TagEdit::~TagEdit()
{}
/*! /*!
* \brief Assigns the specified \a tag to the edit. * \brief Assigns the specified \a tag to the edit.
* \param updateUi Specifies whether the UI of should be updated. * \param updateUi Specifies whether the UI of should be updated.

View File

@ -31,7 +31,6 @@ class TagEdit : public QWidget
public: public:
explicit TagEdit(QWidget *parent = nullptr); explicit TagEdit(QWidget *parent = nullptr);
~TagEdit();
const QList<Media::Tag *> &tags() const; const QList<Media::Tag *> &tags() const;
void setTag(Media::Tag *tag, bool updateUi = true); void setTag(Media::Tag *tag, bool updateUi = true);
void setTags(const QList<Media::Tag *> &tags, bool updateUi = true); void setTags(const QList<Media::Tag *> &tags, bool updateUi = true);

View File

@ -49,11 +49,6 @@ using namespace ConversionUtilities;
namespace QtGui { namespace QtGui {
/*
TRANSLATOR QtGui::TagFieldEdit
Necessary for lupdate.
*/
/*! /*!
* \class QtGui::TagFieldEdit * \class QtGui::TagFieldEdit
* \brief The TagFieldEdit widget allows the user to edit a specified tag field. * \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(); 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. * \brief Assigns the specified \a tags and sets the specified \a fields using the given \a previousValueHandling.
* *

View File

@ -39,7 +39,6 @@ class TagFieldEdit : public QWidget
public: public:
explicit TagFieldEdit(const QList<Media::Tag *> &tags, Media::KnownField field, QWidget *parent = nullptr); explicit TagFieldEdit(const QList<Media::Tag *> &tags, Media::KnownField field, QWidget *parent = nullptr);
virtual ~TagFieldEdit();
const QList<Media::Tag *> &tags() const; const QList<Media::Tag *> &tags() const;
Media::KnownField field() const; Media::KnownField field() const;

View File

@ -7,6 +7,7 @@
namespace RenamingUtility { namespace RenamingUtility {
enum class ActionType { enum class ActionType {
None,
Rename, Rename,
Skip Skip
}; };

View File

@ -1,13 +1,12 @@
#include "./renamingengine.h" #include "./renamingengine.h"
#include "./filesystemitemmodel.h" #include "./filesystemitemmodel.h"
#include "./filteredfilesystemitemmodel.h" #include "./filteredfilesystemitemmodel.h"
#include "./scriptfunctions.h" #include "./tageditorobject.h"
#include <c++utilities/misc/memory.h> #include <c++utilities/misc/memory.h>
#include <QDir> #include <QDir>
#include <QScriptEngine> #include <QStringBuilder>
#include <QScriptProgram>
#include <thread> #include <thread>
@ -15,14 +14,10 @@ using namespace std;
namespace RenamingUtility { namespace RenamingUtility {
/*
TRANSLATOR RenamingUtility::RemamingEngine
Necessary for lupdate.
*/
RemamingEngine::RemamingEngine(QObject *parent) : RemamingEngine::RemamingEngine(QObject *parent) :
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_itemsProcessed(0),
m_errorsOccured(0), m_errorsOccured(0),
m_aborted(false), m_aborted(false),
@ -31,21 +26,40 @@ RemamingEngine::RemamingEngine(QObject *parent) :
m_currentModel(nullptr), m_currentModel(nullptr),
m_previewModel(nullptr) m_previewModel(nullptr)
{ {
m_engine.globalObject().setProperty(QStringLiteral("tageditor"), m_tagEditorJsObj);
connect(this, &RemamingEngine::previewGenerated, this, &RemamingEngine::processPreviewGenerated); connect(this, &RemamingEngine::previewGenerated, this, &RemamingEngine::processPreviewGenerated);
connect(this, &RemamingEngine::changingsApplied, this, &RemamingEngine::processChangingsApplied); 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()) { if(!m_mutex.try_lock()) {
return false; return false;
} }
lock_guard<mutex> guard(m_mutex, adopt_lock); lock_guard<mutex> guard(m_mutex, adopt_lock);
setRootItem(); setRootItem();
m_program = scriptProgram;
m_includeSubdirs = includeSubdirs; m_includeSubdirs = includeSubdirs;
m_dir = rootDirectory; m_dir = rootDirectory;
auto startFunc = [this] () { auto startFunc = [this] () {
@ -54,7 +68,6 @@ bool RemamingEngine::generatePreview(const QScriptProgram &scriptProgram, const
m_aborted.store(false); m_aborted.store(false);
m_itemsProcessed = 0; m_itemsProcessed = 0;
m_errorsOccured = 0; m_errorsOccured = 0;
m_go.setProperty("persistent", m_persistent = m_engine.newObject(), QScriptValue::Undeletable);
m_newlyGeneratedRootItem = generatePreview(m_dir); m_newlyGeneratedRootItem = generatePreview(m_dir);
} }
emit previewGenerated(); 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); auto item = make_unique<FileSystemItem>(ItemStatus::Current, ItemType::Dir, dir.dirName(), parent);
item->setApplied(false); item->setApplied(false);
QFileInfoList entries = dir.entryInfoList(); for(const QFileInfo &entry : dir.entryInfoList()) {
foreach(const QFileInfo &entry, entries) {
if(entry.fileName() == QLatin1String("..") if(entry.fileName() == QLatin1String("..")
|| entry.fileName() == QLatin1String(".")) { || entry.fileName() == QLatin1String(".")) {
continue; continue;
@ -280,7 +292,7 @@ void RemamingEngine::applyChangings(FileSystemItem *parentItem)
void RemamingEngine::setError(const QList<FileSystemItem *> items) void RemamingEngine::setError(const QList<FileSystemItem *> items)
{ {
foreach(FileSystemItem *item, items) { for(FileSystemItem *item : items) {
item->setErrorOccured(true); item->setErrorOccured(true);
item->setNote(tr("skipped due to error of superior item")); 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) 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 // execute script
setupGlobalObject(fileInfo, item); auto scriptResult = m_program.call();
QScriptValue res = m_engine.evaluate(m_program); if(scriptResult.isError()) {
if(m_engine.hasUncaughtException()) {
// handle error // handle error
item->setErrorOccured(true); item->setErrorOccured(true);
item->setNote(res.toString()); item->setNote(scriptResult.toString());
m_engine.clearExceptions();
} else { } else {
// create preview for action // create preview for action
QScriptValue newName = m_go.property("newName"); const QString &newName = m_tagEditorQObj->newName();
QScriptValue newRelativeDirectory = m_go.property("newRelativeDirectory"); const QString &newRelativeDirectory = m_tagEditorQObj->newRelativeDirectory();
ActionType action = ActionType::Skip; switch(m_tagEditorQObj->action()) {
if(m_go.property("action").isNumber()) { case ActionType::None:
action = static_cast<ActionType>(m_go.property("action").toInt32()); item->setNote(tr("no action specified"));
} break;
switch(action) {
case ActionType::Rename: case ActionType::Rename:
if(newRelativeDirectory.isString()) { if(!newRelativeDirectory.isEmpty()) {
FileSystemItem *counterpartParent = item->root()->makeChildAvailable(newRelativeDirectory.toString()); FileSystemItem *counterpartParent = item->root()->makeChildAvailable(newRelativeDirectory);
if(counterpartParent->status() == ItemStatus::New if(counterpartParent->status() == ItemStatus::New
&& counterpartParent->note().isEmpty()) { && counterpartParent->note().isEmpty()) {
counterpartParent->setNote(tr("will be created")); counterpartParent->setNote(tr("will be created"));
} }
QString counterpartName = newName.isString() const QString &counterpartName = newName.isEmpty() ? item->name() : newName;
? newName.toString()
: item->name();
if(counterpartParent->findChild(counterpartName, item)) { if(counterpartParent->findChild(counterpartName, item)) {
item->setNote(tr("name is already used at new location")); item->setNote(tr("name is already used at new location"));
item->setErrorOccured(true); item->setErrorOccured(true);
@ -324,8 +333,8 @@ void RemamingEngine::executeScriptForItem(const QFileInfo &fileInfo, FileSystemI
counterpart->setCheckable(true); counterpart->setCheckable(true);
counterpart->setChecked(true); counterpart->setChecked(true);
} }
} else if(newName.isString()) { } else if(!newName.isEmpty()) {
item->setNewName(newName.toString()); item->setNewName(newName);
} }
if(FileSystemItem *newItem = item->counterpart()) { if(FileSystemItem *newItem = item->counterpart()) {
if((newItem->name().isEmpty() || newItem->name() == item->name()) if((newItem->name().isEmpty() || newItem->name() == item->name())
@ -347,34 +356,8 @@ void RemamingEngine::executeScriptForItem(const QFileInfo &fileInfo, FileSystemI
break; break;
default: default:
item->setNote(tr("skipped")); 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 } // namespace RenamingUtility

View File

@ -2,26 +2,31 @@
#define RENAMINGUTILITY_RENAMINGENGINE_H #define RENAMINGUTILITY_RENAMINGENGINE_H
#include "./filesystemitem.h" #include "./filesystemitem.h"
#include "./scriptdefs.h"
#include <QObject> #include <QObject>
#include <QList> #include <QList>
#include <QDir> #include <QDir>
#include <QScriptProgram>
#include <QScriptEngine> #if TAGEDITOR_USE_JSENGINE
#include <QScriptValue> # include <QJSEngine>
# include <QJSValue>
#else
# include <QScriptEngine>
# include <QScriptValue>
#endif
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <atomic> #include <atomic>
QT_FORWARD_DECLARE_CLASS(QFileInfo) QT_FORWARD_DECLARE_CLASS(QFileInfo)
QT_FORWARD_DECLARE_CLASS(QScriptProgram)
QT_FORWARD_DECLARE_CLASS(QScriptContext)
namespace RenamingUtility { namespace RenamingUtility {
class FileSystemItemModel; class FileSystemItemModel;
class FilteredFileSystemItemModel; class FilteredFileSystemItemModel;
class TagEditorObject;
class RemamingEngine : public QObject class RemamingEngine : public QObject
{ {
@ -29,10 +34,11 @@ class RemamingEngine : public QObject
public: public:
RemamingEngine(QObject *parent = nullptr); RemamingEngine(QObject *parent = nullptr);
virtual ~RemamingEngine();
FileSystemItem *rootItem() const; 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; const QDir &rootDirectory() const;
bool subdirsIncluded() const; bool subdirsIncluded() const;
bool isBusy(); bool isBusy();
@ -41,9 +47,11 @@ public:
FileSystemItemModel *model(); FileSystemItemModel *model();
FilteredFileSystemItemModel *currentModel(); FilteredFileSystemItemModel *currentModel();
FilteredFileSystemItemModel *previewModel(); FilteredFileSystemItemModel *previewModel();
const QString &errorMessage() const;
int errorLineNumber() const;
public slots: public slots:
bool generatePreview(const QScriptProgram &scriptProgram, const QDir &rootDirectory, bool includeSubdirs); bool generatePreview(const QDir &rootDirectory, bool includeSubdirs);
bool applyChangings(); bool applyChangings();
void abort(); void abort();
@ -63,23 +71,24 @@ private:
void applyChangings(FileSystemItem *parentItem); void applyChangings(FileSystemItem *parentItem);
static void setError(const QList<FileSystemItem *> items); static void setError(const QList<FileSystemItem *> items);
void executeScriptForItem(const QFileInfo &fileInfo, FileSystemItem *item); void executeScriptForItem(const QFileInfo &fileInfo, FileSystemItem *item);
void setupGlobalObject(const QFileInfo &file, FileSystemItem *item);
QScriptEngine m_engine; TagEditorObject *m_tagEditorQObj;
QScriptValue m_go; TAGEDITOR_JS_ENGINE m_engine;
QScriptValue m_persistent; TAGEDITOR_JS_VALUE m_tagEditorJsObj;
std::unique_ptr<FileSystemItem> m_rootItem; std::unique_ptr<FileSystemItem> m_rootItem;
std::unique_ptr<FileSystemItem> m_newlyGeneratedRootItem; std::unique_ptr<FileSystemItem> m_newlyGeneratedRootItem;
int m_itemsProcessed; int m_itemsProcessed;
int m_errorsOccured; int m_errorsOccured;
std::atomic<bool> m_aborted; std::atomic<bool> m_aborted;
QScriptProgram m_program; TAGEDITOR_JS_VALUE m_program;
QDir m_dir; QDir m_dir;
bool m_includeSubdirs; bool m_includeSubdirs;
std::mutex m_mutex; std::mutex m_mutex;
FileSystemItemModel *m_model; FileSystemItemModel *m_model;
FilteredFileSystemItemModel *m_currentModel; FilteredFileSystemItemModel *m_currentModel;
FilteredFileSystemItemModel *m_previewModel; FilteredFileSystemItemModel *m_previewModel;
QString m_errorMessage;
int m_errorLineNumber;
}; };
inline FileSystemItem *RemamingEngine::rootItem() const inline FileSystemItem *RemamingEngine::rootItem() const
@ -87,7 +96,7 @@ inline FileSystemItem *RemamingEngine::rootItem() const
return m_rootItem.get(); return m_rootItem.get();
} }
inline const QScriptProgram &RemamingEngine::scriptProgram() const inline const TAGEDITOR_JS_VALUE &RemamingEngine::scriptProgram() const
{ {
return m_program; return m_program;
} }
@ -102,6 +111,16 @@ inline bool RemamingEngine::subdirsIncluded() const
return m_includeSubdirs; return m_includeSubdirs;
} }
inline const QString &RemamingEngine::errorMessage() const
{
return m_errorMessage;
}
inline int RemamingEngine::errorLineNumber() const
{
return m_errorLineNumber;
}
} // namespace RenamingUtility } // namespace RenamingUtility
#endif // RENAMINGUTILITY_RENAMINGENGINE_H #endif // RENAMINGUTILITY_RENAMINGENGINE_H

View File

@ -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

View File

@ -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 &notificationsObject, const StatusProvider &statusProvider)
{
quint32 counter = 0;
for(const auto &notification : 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

View File

@ -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

View File

@ -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 &notificationsObject, const StatusProvider &statusProvider)
{
quint32 counter = 0;
for(const auto &notification : 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

View File

@ -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 &currentPath() const;
const QString &currentName() const;
const QString &currentRelativeDirectory() 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

View File

@ -21,27 +21,27 @@ var distDir = false;
// string used for "miscellaneous" category // string used for "miscellaneous" category
var misc = "misc"; var misc = "misc";
// define helper functions // define some helper functions
/*! /*!
* \brief Returns whether the specified \a value is not undefined * Returns whether the specified \a value is not undefined
and not an empty string. * and not an empty string.
*/ */
function notEmpty(value) { function notEmpty(value) {
return value !== undefined && value !== ""; return value !== undefined && value !== "";
} }
/*! /*!
* \brief Returns whether the specified \a value is not undefined * Returns whether the specified \a value is not undefined
and not zero. * and not zero.
*/ */
function notNull(value) { function notNull(value) {
return value !== undefined && value !== 0; return value !== undefined && value !== 0;
} }
/*! /*!
* \brief Returns the string representation of \a pos using at least as * Returns the string representation of \a pos using at least as
many digits as \a total has. * many digits as \a total has.
*/ */
function appropriateDigitCount(pos, total) { function appropriateDigitCount(pos, total) {
var res = pos + ""; 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 * Returns a copy of the specified \a name with characters that might be
avoided in file names striped out. * avoided in file names striped out.
*/ */
function validFileName(name) { function validFileName(name) {
if(name !== undefined) { if(name !== undefined) {
@ -65,8 +65,8 @@ function validFileName(name) {
} }
/*! /*!
* \brief Returns a copy of the specified \a name with characters that might be * Returns a copy of the specified \a name with characters that might be
avoided in directory names striped out. * avoided in directory names striped out.
*/ */
function validDirectoryName(name) { function validDirectoryName(name) {
if(name !== undefined) { if(name !== undefined) {
@ -79,21 +79,21 @@ function validDirectoryName(name) {
// the actual script // the actual script
// check whether we have to deal with a file or a directory // 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 // 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 var tag = fileInfo.tag; // get the tag information
// read title and track number from the file name using the built-in parseFileName function // 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 // read the suffix from the file info object to filter backup and temporary files
if(fileInfo.currentName === "desktop.ini") { if(fileInfo.currentName === "desktop.ini") {
action = actionType.skip; // skip these files tageditor.skip(); // skip these files
} else if(fileInfo.currentSuffix === "bak") { } else if(fileInfo.currentSuffix === "bak") {
// filter backup files by setting newRelativeDirectory to put them in a separate directory // filter backup by putting them in a separate directory
newRelativeDirectory = "backups"; tageditor.move("backups");
} else if(fileInfo.currentSuffix === "tmp") { } else if(fileInfo.currentSuffix === "tmp") {
// filter temporary files in the same way as backup files // filter temporary files in the same way as backup files
newRelativeDirectory = "temp"; tageditor.move("temp");
} else { } else {
// define an array for the fields; will be joined later // define an array for the fields; will be joined later
var fields = []; var fields = [];
@ -135,7 +135,7 @@ if(isFile) {
fields.push(appropriateDigitCount(infoFromFileName.trackPos, 10)); fields.push(appropriateDigitCount(infoFromFileName.trackPos, 10));
} }
// join the first part of the new name // join the first part of the new name
newName = fields.join(separator); var newName = fields.join(separator);
// get the title // get the title
var title = validFileName(tag.title); var title = validFileName(tag.title);
// append the title (if configured and present) // append the title (if configured and present)
@ -163,6 +163,8 @@ if(isFile) {
if(notEmpty(suffix)) { if(notEmpty(suffix)) {
newName = newName.concat(".", suffix); newName = newName.concat(".", suffix);
} }
// apply new name
tageditor.rename(newName);
// set the distribution directory // set the distribution directory
if(distDir) { if(distDir) {
var path = [distDir]; var path = [distDir];
@ -185,13 +187,11 @@ if(isFile) {
if(tag.diskTotal >= 2) { if(tag.diskTotal >= 2) {
path.push("Disk " + appropriateDigitCount(tag.diskPos, tag.diskTotal)); 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" } else if(tageditor.isDir) {
// (this is the default action, actually there is no need to set it explicitly) // skip directories in this example script
action = actionType.rename; tageditor.skip();
} else if(isDir) {
// skip directories in this example script by setting the action to "actionType.skip"
action = actionType.skip;
} }

View File

@ -15,7 +15,7 @@ VERSION = 1.3.0
# basic configuration: application # basic configuration: application
TEMPLATE = app TEMPLATE = app
QT += core gui widgets script QT += core gui widgets
# use webkitwidgets if available; otherwise use webenginewidgets # use webkitwidgets if available; otherwise use webenginewidgets
!forcewebengine:qtHaveModule(webkitwidgets) { !forcewebengine:qtHaveModule(webkitwidgets) {
QT += webkitwidgets QT += webkitwidgets
@ -23,9 +23,17 @@ QT += core gui widgets script
QT += webenginewidgets QT += webenginewidgets
DEFINES += TAGEDITOR_USE_WEBENGINE 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 # add project files
HEADERS += application/main.h \ HEADERS += \
application/main.h \
application/knownfieldmodel.h \ application/knownfieldmodel.h \
application/settings.h \ application/settings.h \
gui/filefilterproxymodel.h \ gui/filefilterproxymodel.h \
@ -44,7 +52,8 @@ HEADERS += application/main.h \
renamingutility/filesystemitemmodel.h \ renamingutility/filesystemitemmodel.h \
renamingutility/filteredfilesystemitemmodel.h \ renamingutility/filteredfilesystemitemmodel.h \
renamingutility/renamingengine.h \ renamingutility/renamingengine.h \
renamingutility/scriptfunctions.h \ renamingutility/scriptdefs.h \
renamingutility/tageditorobject.h \
misc/htmlinfo.h \ misc/htmlinfo.h \
gui/previousvaluehandling.h \ gui/previousvaluehandling.h \
gui/initiate.h \ gui/initiate.h \
@ -55,7 +64,8 @@ HEADERS += application/main.h \
gui/attachmentsedit.h \ gui/attachmentsedit.h \
gui/codeedit.h gui/codeedit.h
SOURCES += application/main.cpp \ SOURCES += \
application/main.cpp \
application/knownfieldmodel.cpp \ application/knownfieldmodel.cpp \
application/settings.cpp \ application/settings.cpp \
gui/filefilterproxymodel.cpp \ gui/filefilterproxymodel.cpp \
@ -74,9 +84,8 @@ SOURCES += application/main.cpp \
renamingutility/filesystemitemmodel.cpp \ renamingutility/filesystemitemmodel.cpp \
renamingutility/filteredfilesystemitemmodel.cpp \ renamingutility/filteredfilesystemitemmodel.cpp \
renamingutility/renamingengine.cpp \ renamingutility/renamingengine.cpp \
renamingutility/scriptfunctions.cpp \ renamingutility/tageditorobject.cpp \
misc/htmlinfo.cpp \ misc/htmlinfo.cpp \
gui/previousvaluehandling.cpp \
gui/initiate.cpp \ gui/initiate.cpp \
cli/mainfeatures.cpp \ cli/mainfeatures.cpp \
misc/utility.cpp \ misc/utility.cpp \