diff --git a/CMakeLists.txt b/CMakeLists.txt index 9737674..661f200 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 ) diff --git a/README.md b/README.md index b0b4e0e..e2f0fe8 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/gui/filefilterproxymodel.cpp b/gui/filefilterproxymodel.cpp index 0ce2cfd..acd08a0 100644 --- a/gui/filefilterproxymodel.cpp +++ b/gui/filefilterproxymodel.cpp @@ -4,11 +4,6 @@ namespace QtGui { -/* - TRANSLATOR QtGui::FileFilterProxyModel - Necessary for lupdate. -*/ - FileFilterProxyModel::FileFilterProxyModel(QObject *parent) : QSortFilterProxyModel(parent), m_filterEnabled(true) diff --git a/gui/infowidgetbase.cpp b/gui/infowidgetbase.cpp index 0a6b0f2..1e63dcd 100644 --- a/gui/infowidgetbase.cpp +++ b/gui/infowidgetbase.cpp @@ -23,11 +23,6 @@ using namespace Media; namespace QtGui { -/* - TRANSLATOR QtGui::InfoWidgetBase - Necessary for lupdate. -*/ - InfoWidgetBase::InfoWidgetBase(QWidget *parent) : QWidget(parent), m_notificationModel(nullptr) diff --git a/gui/initiate.cpp b/gui/initiate.cpp index b6663bc..18cce35 100644 --- a/gui/initiate.cpp +++ b/gui/initiate.cpp @@ -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 diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp index d606a06..d4efd58 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -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. */ diff --git a/gui/notificationlabel.cpp b/gui/notificationlabel.cpp index f32970b..988db96 100644 --- a/gui/notificationlabel.cpp +++ b/gui/notificationlabel.cpp @@ -27,9 +27,6 @@ NotificationLabel::NotificationLabel(QWidget *parent) : m_updateTimer.setInterval(80); } -NotificationLabel::~NotificationLabel() -{} - void NotificationLabel::paintEvent(QPaintEvent *event) { QStyle *style = QWidget::style(); diff --git a/gui/notificationlabel.h b/gui/notificationlabel.h index 72573c3..73d1396 100644 --- a/gui/notificationlabel.h +++ b/gui/notificationlabel.h @@ -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; diff --git a/gui/notificationmodel.cpp b/gui/notificationmodel.cpp index 0d1155b..aa7a8e9 100644 --- a/gui/notificationmodel.cpp +++ b/gui/notificationmodel.cpp @@ -12,11 +12,6 @@ using namespace Media; namespace QtGui { -/* - TRANSLATOR QtGui::NotificationModel - Necessary for lupdate. -*/ - NotificationModel::NotificationModel(QObject *parent) : QAbstractListModel(parent) {} diff --git a/gui/pathlineedit.cpp b/gui/pathlineedit.cpp index 26468f1..790368f 100644 --- a/gui/pathlineedit.cpp +++ b/gui/pathlineedit.cpp @@ -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()) { diff --git a/gui/pathlineedit.h b/gui/pathlineedit.h index 87ee01e..4839991 100644 --- a/gui/pathlineedit.h +++ b/gui/pathlineedit.h @@ -18,7 +18,6 @@ class PathLineEdit : public Widgets::ClearLineEdit public: explicit PathLineEdit(QWidget *parent = nullptr); - virtual ~PathLineEdit(); QAbstractItemModel *completionModel() const; void setCompletionModel(QAbstractItemModel *model); diff --git a/gui/picturepreviewselection.cpp b/gui/picturepreviewselection.cpp index a2c0bdd..640cb5c 100644 --- a/gui/picturepreviewselection.cpp +++ b/gui/picturepreviewselection.cpp @@ -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() {} diff --git a/gui/picturepreviewselection.h b/gui/picturepreviewselection.h index 8ec3d3a..70cd4d1 100644 --- a/gui/picturepreviewselection.h +++ b/gui/picturepreviewselection.h @@ -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; diff --git a/gui/previousvaluehandling.cpp b/gui/previousvaluehandling.cpp deleted file mode 100644 index 93d17a1..0000000 --- a/gui/previousvaluehandling.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "./previousvaluehandling.h" - -namespace QtGui { - -} diff --git a/gui/renamefilesdialog.cpp b/gui/renamefilesdialog.cpp index 49bfa3e..966f5ad 100644 --- a/gui/renamefilesdialog.cpp +++ b/gui/renamefilesdialog.cpp @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -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); diff --git a/gui/tagedit.cpp b/gui/tagedit.cpp index cdf896a..f753c26 100644 --- a/gui/tagedit.cpp +++ b/gui/tagedit.cpp @@ -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. diff --git a/gui/tagedit.h b/gui/tagedit.h index 92cdfa3..903d458 100644 --- a/gui/tagedit.h +++ b/gui/tagedit.h @@ -31,7 +31,6 @@ class TagEdit : public QWidget public: explicit TagEdit(QWidget *parent = nullptr); - ~TagEdit(); const QList &tags() const; void setTag(Media::Tag *tag, bool updateUi = true); void setTags(const QList &tags, bool updateUi = true); diff --git a/gui/tagfieldedit.cpp b/gui/tagfieldedit.cpp index aeddea7..4c0c808 100644 --- a/gui/tagfieldedit.cpp +++ b/gui/tagfieldedit.cpp @@ -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 &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. * diff --git a/gui/tagfieldedit.h b/gui/tagfieldedit.h index 5ee4996..fb95a19 100644 --- a/gui/tagfieldedit.h +++ b/gui/tagfieldedit.h @@ -39,7 +39,6 @@ class TagFieldEdit : public QWidget public: explicit TagFieldEdit(const QList &tags, Media::KnownField field, QWidget *parent = nullptr); - virtual ~TagFieldEdit(); const QList &tags() const; Media::KnownField field() const; diff --git a/renamingutility/filesystemitem.h b/renamingutility/filesystemitem.h index 97061b5..c979fe2 100644 --- a/renamingutility/filesystemitem.h +++ b/renamingutility/filesystemitem.h @@ -7,6 +7,7 @@ namespace RenamingUtility { enum class ActionType { + None, Rename, Skip }; diff --git a/renamingutility/renamingengine.cpp b/renamingutility/renamingengine.cpp index 1a28b12..8a699d2 100644 --- a/renamingutility/renamingengine.cpp +++ b/renamingutility/renamingengine.cpp @@ -1,13 +1,12 @@ #include "./renamingengine.h" #include "./filesystemitemmodel.h" #include "./filteredfilesystemitemmodel.h" -#include "./scriptfunctions.h" +#include "./tageditorobject.h" #include #include -#include -#include +#include #include @@ -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 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 RemamingEngine::generatePreview(const QDir &dir, File { auto item = make_unique(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 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 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(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(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(ActionType::Rename)), QScriptValue::ReadOnly); - actionObject.setProperty("skip", QScriptValue(static_cast(ActionType::Skip)), QScriptValue::ReadOnly); - m_go.setProperty("actionType", actionObject, QScriptValue::ReadOnly); - m_engine.setGlobalObject(m_go); -} - } // namespace RenamingUtility diff --git a/renamingutility/renamingengine.h b/renamingutility/renamingengine.h index 5253f38..e573f5b 100644 --- a/renamingutility/renamingengine.h +++ b/renamingutility/renamingengine.h @@ -2,26 +2,31 @@ #define RENAMINGUTILITY_RENAMINGENGINE_H #include "./filesystemitem.h" +#include "./scriptdefs.h" #include #include #include -#include -#include -#include + +#if TAGEDITOR_USE_JSENGINE +# include +# include +#else +# include +# include +#endif #include #include #include 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 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 m_rootItem; std::unique_ptr m_newlyGeneratedRootItem; int m_itemsProcessed; int m_errorsOccured; std::atomic 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 diff --git a/renamingutility/scriptdefs.h b/renamingutility/scriptdefs.h new file mode 100644 index 0000000..5bebbe1 --- /dev/null +++ b/renamingutility/scriptdefs.h @@ -0,0 +1,28 @@ +#ifndef SCRIPTDEFS_H +#define SCRIPTDEFS_H + +#include + +#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 diff --git a/renamingutility/scriptfunctions.cpp b/renamingutility/scriptfunctions.cpp deleted file mode 100644 index b44105f..0000000 --- a/renamingutility/scriptfunctions.cpp +++ /dev/null @@ -1,200 +0,0 @@ -#include "./scriptfunctions.h" - -#include "../misc/utility.h" - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include - -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 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 diff --git a/renamingutility/scriptfunctions.h b/renamingutility/scriptfunctions.h deleted file mode 100644 index 6ab501d..0000000 --- a/renamingutility/scriptfunctions.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef RENAMINGUTILITY_SCRIPTFUNCTIONS_H -#define RENAMINGUTILITY_SCRIPTFUNCTIONS_H - -#include - -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 diff --git a/renamingutility/tageditorobject.cpp b/renamingutility/tageditorobject.cpp new file mode 100644 index 0000000..1dc6478 --- /dev/null +++ b/renamingutility/tageditorobject.cpp @@ -0,0 +1,250 @@ +#include "./tageditorobject.h" +#include "./filesystemitem.h" + +#include "../misc/utility.h" + +#include +#include +#include +#include + +#include + +#include + +#ifdef TAGEDITOR_USE_JSENGINE +# include +# include +#else +# include +# include +#endif + +#include + +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 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 diff --git a/renamingutility/tageditorobject.h b/renamingutility/tageditorobject.h new file mode 100644 index 0000000..8d6c2e2 --- /dev/null +++ b/renamingutility/tageditorobject.h @@ -0,0 +1,75 @@ +#ifndef RENAMINGUTILITY_SCRIPTFUNCTIONS_H +#define RENAMINGUTILITY_SCRIPTFUNCTIONS_H + +#include "./scriptdefs.h" + +#include +#ifdef TAGEDITOR_USE_JSENGINE +# include +#else +# include +#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 diff --git a/resources/scripts/renamefiles/example1.js b/resources/scripts/renamefiles/example1.js index 9e8547b..6c91860 100644 --- a/resources/scripts/renamefiles/example1.js +++ b/resources/scripts/renamefiles/example1.js @@ -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(); } diff --git a/tageditor.pro b/tageditor.pro index 7b8ccb9..1f1fb83 100644 --- a/tageditor.pro +++ b/tageditor.pro @@ -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 \