Scripting module
This commit is contained in:
+10
-7
@@ -17,7 +17,7 @@ if(SANITIZE_ADDRESS_LEAK)
|
|||||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fsanitize=address -fsanitize=leak")
|
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fsanitize=address -fsanitize=leak")
|
||||||
endif(SANITIZE_ADDRESS_LEAK)
|
endif(SANITIZE_ADDRESS_LEAK)
|
||||||
|
|
||||||
find_package(Qt6 COMPONENTS Widgets Sql OpenGLWidgets REQUIRED)
|
find_package(Qt6 COMPONENTS Widgets Sql OpenGLWidgets Qml REQUIRED)
|
||||||
find_library(GSL_LIB gsl REQUIRED)
|
find_library(GSL_LIB gsl REQUIRED)
|
||||||
find_library(GSLCBLAS_LIB gslcblas REQUIRED)
|
find_library(GSLCBLAS_LIB gslcblas REQUIRED)
|
||||||
find_library(EXIF_LIB exif REQUIRED)
|
find_library(EXIF_LIB exif REQUIRED)
|
||||||
@@ -29,6 +29,7 @@ add_subdirectory(libXISF)
|
|||||||
|
|
||||||
set(TENMON_SRC
|
set(TENMON_SRC
|
||||||
about.cpp about.h
|
about.cpp about.h
|
||||||
|
batchprocessing.cpp batchprocessing.h batchprocessing.ui
|
||||||
database.cpp database.h
|
database.cpp database.h
|
||||||
databaseview.cpp databaseview.h
|
databaseview.cpp databaseview.h
|
||||||
delete.cpp
|
delete.cpp
|
||||||
@@ -44,6 +45,7 @@ set(TENMON_SRC
|
|||||||
markedfiles.cpp markedfiles.h
|
markedfiles.cpp markedfiles.h
|
||||||
rawimage.cpp rawimage.h
|
rawimage.cpp rawimage.h
|
||||||
rawimage_sse.cpp
|
rawimage_sse.cpp
|
||||||
|
scriptengine.cpp scriptengine.h
|
||||||
settingsdialog.cpp settingsdialog.h
|
settingsdialog.cpp settingsdialog.h
|
||||||
starfit.cpp starfit.h
|
starfit.cpp starfit.h
|
||||||
statusbar.cpp statusbar.h
|
statusbar.cpp statusbar.h
|
||||||
@@ -67,11 +69,12 @@ elseif(APPLE)
|
|||||||
set_source_files_properties(${tenmon_ICON} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
|
set_source_files_properties(${tenmon_ICON} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
|
||||||
else()
|
else()
|
||||||
set(tenmon_ICON "")
|
set(tenmon_ICON "")
|
||||||
|
find_package(Qt6 COMPONENTS DBus REQUIRED)
|
||||||
find_package(PkgConfig REQUIRED)
|
find_package(PkgConfig REQUIRED)
|
||||||
pkg_search_module(GIO REQUIRED gio-2.0)
|
pkg_search_module(GIO REQUIRED gio-2.0)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_executable(tenmon WIN32 MACOSX_BUNDLE ${tenmon_ICON} ${TENMON_SRC})
|
qt_add_executable(tenmon WIN32 MACOSX_BUNDLE ${tenmon_ICON} ${TENMON_SRC})
|
||||||
|
|
||||||
find_path(FITS_INCLUDE fitsio2.h PATH_SUFFIXES cfitsio REQUIRED)
|
find_path(FITS_INCLUDE fitsio2.h PATH_SUFFIXES cfitsio REQUIRED)
|
||||||
target_include_directories(tenmon PRIVATE ${FITS_INCLUDE} ${CMAKE_BINARY_DIR} ${libXISF_SOURCE_DIR})
|
target_include_directories(tenmon PRIVATE ${FITS_INCLUDE} ${CMAKE_BINARY_DIR} ${libXISF_SOURCE_DIR})
|
||||||
@@ -80,16 +83,16 @@ if(UNIX AND NOT APPLE)
|
|||||||
target_include_directories(tenmon PRIVATE ${GIO_INCLUDE_DIRS})
|
target_include_directories(tenmon PRIVATE ${GIO_INCLUDE_DIRS})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_link_libraries(tenmon Qt6::Widgets Qt6::Sql Qt6::OpenGLWidgets ${GSL_LIB} ${GSLCBLAS_LIB} ${EXIF_LIB} ${FITS_LIB} ${RAW_LIB} ${WCS_LIB} XISF)
|
target_link_libraries(tenmon PRIVATE Qt6::Widgets Qt6::Sql Qt6::OpenGLWidgets Qt6::Qml ${GSL_LIB} ${GSLCBLAS_LIB} ${EXIF_LIB} ${FITS_LIB} ${RAW_LIB} ${WCS_LIB} XISF)
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
target_link_libraries(tenmon "-framework CoreFoundation")
|
target_link_libraries(tenmon PRIVATE "-framework CoreFoundation")
|
||||||
else()
|
elseif(UNIX)
|
||||||
target_link_libraries(tenmon ${GIO_LDFLAGS})
|
target_link_libraries(tenmon PRIVATE Qt6::DBus ${GIO_LDFLAGS})
|
||||||
endif(APPLE)
|
endif(APPLE)
|
||||||
|
|
||||||
if(LIBRAW_STATIC)
|
if(LIBRAW_STATIC)
|
||||||
add_compile_definitions("LIBRAW_NODLL")
|
add_compile_definitions("LIBRAW_NODLL")
|
||||||
target_link_libraries(tenmon jasper)
|
target_link_libraries(tenmon PRIVATE jasper)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
install(TARGETS tenmon BUNDLE DESTINATION .)
|
install(TARGETS tenmon BUNDLE DESTINATION .)
|
||||||
|
|||||||
@@ -0,0 +1,208 @@
|
|||||||
|
#include "batchprocessing.h"
|
||||||
|
#include "ui_batchprocessing.h"
|
||||||
|
#include <QDir>
|
||||||
|
#include <QFileDialog>
|
||||||
|
#include <QStandardPaths>
|
||||||
|
#include <QProcess>
|
||||||
|
#include <QSettings>
|
||||||
|
#include "scriptengine.h"
|
||||||
|
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
#include <QCloseEvent>
|
||||||
|
#include <QDBusConnection>
|
||||||
|
#include <QDBusMessage>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void scanDirectory(const QString &path, QStringList &files)
|
||||||
|
{
|
||||||
|
QFileInfo info(path);
|
||||||
|
if(info.isDir())
|
||||||
|
{
|
||||||
|
QDir dir(path);
|
||||||
|
QStringList entries = dir.entryList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot);
|
||||||
|
for(QString &entry : entries)
|
||||||
|
scanDirectory(dir.absoluteFilePath(entry), files);
|
||||||
|
}
|
||||||
|
else if(info.isFile())
|
||||||
|
{
|
||||||
|
files.append(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList scanDirectories(const QStringList &paths)
|
||||||
|
{
|
||||||
|
QStringList files;
|
||||||
|
|
||||||
|
for(const QString &path : paths)
|
||||||
|
scanDirectory(path, files);
|
||||||
|
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BatchProcessing::scanScriptDir()
|
||||||
|
{
|
||||||
|
_ui->scriptsList->clear();
|
||||||
|
QDir dir(_scriptBasePath);
|
||||||
|
for(const QString &script : dir.entryList(QDir::Files | QDir::Readable))
|
||||||
|
{
|
||||||
|
_ui->scriptsList->addItem(script);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BatchProcessing::BatchProcessing(QWidget *parent) : QDialog(parent)
|
||||||
|
{
|
||||||
|
_ui = new Ui::BatchProcessing;
|
||||||
|
_ui->setupUi(this);
|
||||||
|
|
||||||
|
QStringList scriptsPath = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation);
|
||||||
|
if(scriptsPath.size())
|
||||||
|
{
|
||||||
|
QDir dir(scriptsPath.first());
|
||||||
|
if(!dir.exists("scripts"))
|
||||||
|
{
|
||||||
|
if(!dir.mkpath("scripts"))
|
||||||
|
qWarning() << "Failed to create scripts directory";
|
||||||
|
}
|
||||||
|
dir.cd("scripts");
|
||||||
|
|
||||||
|
_scriptBasePath = dir.absolutePath() + "/";
|
||||||
|
scanScriptDir();
|
||||||
|
_fileWatcher.addPath(_scriptBasePath);
|
||||||
|
connect(&_fileWatcher, &QFileSystemWatcher::directoryChanged, this, &BatchProcessing::scanScriptDir);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qWarning() << "Failed to get app data location";
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(_ui->addFilesButton, &QPushButton::released, this, &BatchProcessing::addFiles);
|
||||||
|
connect(_ui->addDirButton, &QPushButton::released, this, &BatchProcessing::addDir);
|
||||||
|
connect(_ui->removeButton, &QPushButton::released, this, &BatchProcessing::removePath);
|
||||||
|
connect(_ui->removeAllButton, &QPushButton::released, this, &BatchProcessing::removeAllPaths);
|
||||||
|
connect(_ui->startButton, &QPushButton::released, this, &BatchProcessing::runScript);
|
||||||
|
connect(_ui->stopButton, &QPushButton::released, this, &BatchProcessing::stopScript);
|
||||||
|
connect(_ui->browseButton, &QPushButton::released, this, &BatchProcessing::browse);
|
||||||
|
connect(_ui->openScriptsButton, &QPushButton::released, this, &BatchProcessing::openScriptDir);
|
||||||
|
|
||||||
|
QSettings settings;
|
||||||
|
_ui->outputPath->setText(settings.value("batchprocessing/outputpath", QStandardPaths::standardLocations(QStandardPaths::PicturesLocation).first()).toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
BatchProcessing::~BatchProcessing()
|
||||||
|
{
|
||||||
|
delete _engineThread;
|
||||||
|
QSettings settings;
|
||||||
|
settings.setValue("batchprocessing/outputpath", _ui->outputPath->text());
|
||||||
|
delete _ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BatchProcessing::closeEvent(QCloseEvent *event)
|
||||||
|
{
|
||||||
|
if(_engineThread)
|
||||||
|
{
|
||||||
|
QMessageBox::StandardButton ret = QMessageBox::question(this, tr("Interrupt running script?"), tr("Interrupt running script?"));
|
||||||
|
if(ret == QMessageBox::StandardButton::Yes)
|
||||||
|
{
|
||||||
|
_engineThread->interrupt();
|
||||||
|
event->accept();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
event->ignore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
event->accept();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BatchProcessing::addFiles()
|
||||||
|
{
|
||||||
|
QStringList files = QFileDialog::getOpenFileNames(this, tr("Select files"), "/home/nou/Obrázky/astro");
|
||||||
|
_ui->pathsList->addItems(files);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BatchProcessing::addDir()
|
||||||
|
{
|
||||||
|
QString dir = QFileDialog::getExistingDirectory(this, tr("Select directory"), "/home/nou/Obrázky/astro");
|
||||||
|
if(!dir.isEmpty())
|
||||||
|
_ui->pathsList->addItem(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BatchProcessing::removePath()
|
||||||
|
{
|
||||||
|
for(auto &item : _ui->pathsList->selectedItems())
|
||||||
|
delete item;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BatchProcessing::removeAllPaths()
|
||||||
|
{
|
||||||
|
_ui->pathsList->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BatchProcessing::browse()
|
||||||
|
{
|
||||||
|
QString output = QFileDialog::getExistingDirectory(this, tr("Select output directory"), "/home/nou/Obrázky");
|
||||||
|
if(!output.isEmpty())
|
||||||
|
_ui->outputPath->setText(output);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BatchProcessing::openScriptDir()
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_LINUX
|
||||||
|
QDBusConnection con = QDBusConnection::sessionBus();
|
||||||
|
QDBusMessage message = QDBusMessage::createMethodCall("org.freedesktop.FileManager1", "/org/freedesktop/FileManager1", "org.freedesktop.FileManager1", "ShowFolders");
|
||||||
|
QList<QVariant> args = {QStringList(QUrl::fromLocalFile(_scriptBasePath).toString()), QString()};
|
||||||
|
message.setArguments(args);
|
||||||
|
con.call(message);
|
||||||
|
#endif
|
||||||
|
#ifdef Q_OS_WINDOWS
|
||||||
|
QProcess::startDetached("explorer.exe", {QDir::toNativeSeparators(_scriptBasePath)});
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void BatchProcessing::runScript()
|
||||||
|
{
|
||||||
|
_ui->log->clear();
|
||||||
|
auto selectedItems = _ui->scriptsList->selectedItems();
|
||||||
|
if(selectedItems.size())
|
||||||
|
{
|
||||||
|
_engineThread = new Script::ScriptEngineThread(this);
|
||||||
|
connect(_engineThread, &Script::ScriptEngineThread::newMessage, _ui->log, &QTextEdit::append);
|
||||||
|
connect(_engineThread, &Script::ScriptEngineThread::finished, this, &BatchProcessing::scriptFinished);
|
||||||
|
QStringList paths;
|
||||||
|
for(int i=0; i<_ui->pathsList->count(); i++)
|
||||||
|
paths.append(_ui->pathsList->item(i)->text());
|
||||||
|
|
||||||
|
QFileInfo outDir(_ui->outputPath->text());
|
||||||
|
if(outDir.exists() && outDir.isWritable())
|
||||||
|
{
|
||||||
|
_engineThread->setParams(_scriptBasePath + selectedItems.first()->text(), scanDirectories(paths), _ui->outputPath->text());
|
||||||
|
_engineThread->start();
|
||||||
|
_ui->startButton->setEnabled(false);
|
||||||
|
_ui->stopButton->setEnabled(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QMessageBox::warning(this, tr("Invalid output directory"), tr("Output directory path doesn't exist or is not writable"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BatchProcessing::stopScript()
|
||||||
|
{
|
||||||
|
qDebug() << "Stop script";
|
||||||
|
if(_engineThread)
|
||||||
|
_engineThread->interrupt();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BatchProcessing::scriptFinished()
|
||||||
|
{
|
||||||
|
_ui->startButton->setEnabled(true);
|
||||||
|
_ui->stopButton->setEnabled(false);
|
||||||
|
qDebug() << "script finished";
|
||||||
|
delete _engineThread;
|
||||||
|
_engineThread = nullptr;
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
#ifndef BATCHPROCESSING_H
|
||||||
|
#define BATCHPROCESSING_H
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QFileSystemWatcher>
|
||||||
|
#include "scriptengine.h"
|
||||||
|
|
||||||
|
namespace Ui { class BatchProcessing; }
|
||||||
|
|
||||||
|
class BatchProcessing : public QDialog
|
||||||
|
{
|
||||||
|
Ui::BatchProcessing *_ui;
|
||||||
|
QString _scriptBasePath;
|
||||||
|
QFileSystemWatcher _fileWatcher;
|
||||||
|
Script::ScriptEngineThread *_engineThread = nullptr;
|
||||||
|
private slots:
|
||||||
|
void scanScriptDir();
|
||||||
|
public:
|
||||||
|
explicit BatchProcessing(QWidget *parent = nullptr);
|
||||||
|
~BatchProcessing();
|
||||||
|
protected:
|
||||||
|
void closeEvent(QCloseEvent *event);
|
||||||
|
public slots:
|
||||||
|
void scriptDirChanged();
|
||||||
|
void addFiles();
|
||||||
|
void addDir();
|
||||||
|
void removePath();
|
||||||
|
void removeAllPaths();
|
||||||
|
void browse();
|
||||||
|
void openScriptDir();
|
||||||
|
void runScript();
|
||||||
|
void stopScript();
|
||||||
|
void scriptFinished();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BATCHPROCESSING_H
|
||||||
@@ -0,0 +1,226 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>BatchProcessing</class>
|
||||||
|
<widget class="QDialog" name="BatchProcessing">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>1024</width>
|
||||||
|
<height>768</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Batch Processing</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>Input files and directories</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QListWidget" name="pathsList">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>1</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="selectionMode">
|
||||||
|
<enum>QAbstractItemView::MultiSelection</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="addFilesButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Add files</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="addDirButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Add directories</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="removeButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Remove</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="removeAllButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Remove all</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Output directory</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="outputPath">
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="browseButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Browse</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_4">
|
||||||
|
<property name="text">
|
||||||
|
<string>Scripts</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="openScriptsButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Open scripts</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QListWidget" name="scriptsList">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>1</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="text">
|
||||||
|
<string>Log</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTextEdit" name="log">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>4</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>FreeMono</family>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="startButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Start script</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="stopButton">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Stop script</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="closeButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Close</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>closeButton</sender>
|
||||||
|
<signal>released()</signal>
|
||||||
|
<receiver>BatchProcessing</receiver>
|
||||||
|
<slot>close()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>973</x>
|
||||||
|
<y>745</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>511</x>
|
||||||
|
<y>383</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
||||||
+2
-2
@@ -10,12 +10,12 @@ Database::Database(QObject *parent) : QObject(parent)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Database::init()
|
bool Database::init(const QLatin1String &connectionName)
|
||||||
{
|
{
|
||||||
QString path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
|
QString path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
|
||||||
QDir dir(path);
|
QDir dir(path);
|
||||||
|
|
||||||
QSqlDatabase m_database = QSqlDatabase::addDatabase("QSQLITE");
|
QSqlDatabase m_database = QSqlDatabase::addDatabase("QSQLITE", connectionName);
|
||||||
|
|
||||||
if(!dir.mkpath("."))
|
if(!dir.mkpath("."))
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
+1
-1
@@ -24,7 +24,7 @@ class Database : public QObject
|
|||||||
int m_progress;
|
int m_progress;
|
||||||
public:
|
public:
|
||||||
explicit Database(QObject *parent = 0);
|
explicit Database(QObject *parent = 0);
|
||||||
bool init();
|
bool init(const QLatin1String &connectionName = QLatin1String(QSqlDatabase::defaultConnection));
|
||||||
bool mark(const QString &filename);
|
bool mark(const QString &filename);
|
||||||
bool unmark(const QString &filename);
|
bool unmark(const QString &filename);
|
||||||
bool mark(const QStringList &filenames);
|
bool mark(const QStringList &filenames);
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
#include "statusbar.h"
|
#include "statusbar.h"
|
||||||
#include "settingsdialog.h"
|
#include "settingsdialog.h"
|
||||||
#include "histogram.h"
|
#include "histogram.h"
|
||||||
|
#include "batchprocessing.h"
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
@@ -151,6 +152,11 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
|
|||||||
fileMenu->addAction(tr("Index directory"), this, SLOT(indexDir()));
|
fileMenu->addAction(tr("Index directory"), this, SLOT(indexDir()));
|
||||||
fileMenu->addAction(tr("Reindex files"), this, SLOT(reindex()));
|
fileMenu->addAction(tr("Reindex files"), this, SLOT(reindex()));
|
||||||
fileMenu->addAction(tr("Export database to CSV"), this, &MainWindow::exportCSV);
|
fileMenu->addAction(tr("Export database to CSV"), this, &MainWindow::exportCSV);
|
||||||
|
fileMenu->addAction(tr("Batch processing"), [this](){
|
||||||
|
BatchProcessing *batchProcessing = new BatchProcessing(this);
|
||||||
|
batchProcessing->exec();
|
||||||
|
delete batchProcessing;
|
||||||
|
}, Qt::Key_B | Qt::CTRL);
|
||||||
fileMenu->addSeparator();
|
fileMenu->addSeparator();
|
||||||
QAction *liveModeAction = fileMenu->addAction(tr("Live mode"), this, SLOT(liveMode(bool)));
|
QAction *liveModeAction = fileMenu->addAction(tr("Live mode"), this, SLOT(liveMode(bool)));
|
||||||
liveModeAction->setCheckable(true);
|
liveModeAction->setCheckable(true);
|
||||||
|
|||||||
@@ -0,0 +1,224 @@
|
|||||||
|
#include "scriptengine.h"
|
||||||
|
#include <QDir>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QDebug>
|
||||||
|
#include "loadrunable.h"
|
||||||
|
|
||||||
|
namespace Script
|
||||||
|
{
|
||||||
|
|
||||||
|
ScriptEngine::ScriptEngine(QObject *parent) : QObject(parent)
|
||||||
|
, _jsEngine(new QJSEngine(this))
|
||||||
|
, _database(new Database(this))
|
||||||
|
{
|
||||||
|
QJSValue engine = _jsEngine->newQObject(this);
|
||||||
|
_jsEngine->globalObject().setProperty("engine", engine);
|
||||||
|
_database->init(QLatin1String("scriptengine"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptEngine::setParams(const QString &scriptPath, const QStringList &paths, const QString &outputDir)
|
||||||
|
{
|
||||||
|
_scriptPath = scriptPath;
|
||||||
|
_paths = paths;
|
||||||
|
_outputDir = outputDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptEngine::reportError(const QString &message)
|
||||||
|
{
|
||||||
|
_jsEngine->throwError(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString &ScriptEngine::outputDir() const
|
||||||
|
{
|
||||||
|
return _outputDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptEngine::interrupt()
|
||||||
|
{
|
||||||
|
_jsEngine->setInterrupted(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptEngine::log(const QString &message)
|
||||||
|
{
|
||||||
|
emit newMessage(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptEngine::mark(File *file)
|
||||||
|
{
|
||||||
|
_database->mark(file->absoluteFilePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptEngine::unmark(File *file)
|
||||||
|
{
|
||||||
|
_database->unmark(file->absoluteFilePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScriptEngine::isMarked(const File *file) const
|
||||||
|
{
|
||||||
|
return _database->isMarked(file->absoluteFilePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptEngine::run()
|
||||||
|
{
|
||||||
|
QJSValue jsPaths = _jsEngine->newArray(_paths.size());
|
||||||
|
for(qsizetype i=0; i<_paths.size(); i++)
|
||||||
|
jsPaths.setProperty(i, _jsEngine->newQObject(new File(_paths[i], this)));
|
||||||
|
|
||||||
|
_jsEngine->globalObject().setProperty("files", jsPaths);
|
||||||
|
|
||||||
|
QFile scriptFile(_scriptPath);
|
||||||
|
if(!scriptFile.open(QIODevice::ReadOnly))
|
||||||
|
return;
|
||||||
|
|
||||||
|
QTextStream stream(&scriptFile);
|
||||||
|
QString contents = stream.readAll();
|
||||||
|
scriptFile.close();
|
||||||
|
QJSValue result = _jsEngine->evaluate(contents, _scriptPath);
|
||||||
|
qDebug() << result.isError() << result.toString();
|
||||||
|
if(result.isError())
|
||||||
|
{
|
||||||
|
QString error = result.property("name").toString() + " on line " + result.property("lineNumber").toString() + " : " + result.toString();
|
||||||
|
error += "\n" + result.property("stack").toString();
|
||||||
|
emit newMessage(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
emit finished();
|
||||||
|
}
|
||||||
|
|
||||||
|
void File::loadFitsKeywords()
|
||||||
|
{
|
||||||
|
if(!_fitsKeywordsLoaded)
|
||||||
|
{
|
||||||
|
_fitsKeywordsLoaded = true;
|
||||||
|
ImageInfoData info;
|
||||||
|
if(suffix() == "xisf")
|
||||||
|
{
|
||||||
|
readXISFHeader(_path, info);
|
||||||
|
}
|
||||||
|
else if(suffix() == "fits")
|
||||||
|
{
|
||||||
|
readFITSHeader(_path, info);
|
||||||
|
}
|
||||||
|
else return;
|
||||||
|
|
||||||
|
for(const FITSRecord &record : info.fitsHeader)
|
||||||
|
{
|
||||||
|
_fitsKeywords[record.key] = record.value.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
File::File(const QString &path, Script::ScriptEngine *engine) :
|
||||||
|
_engine(engine),
|
||||||
|
_path(path),
|
||||||
|
_info(path)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QString File::fileName() const
|
||||||
|
{
|
||||||
|
return _info.fileName();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString File::absoluteFilePath() const
|
||||||
|
{
|
||||||
|
return _info.absoluteFilePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString File::absolutePath() const
|
||||||
|
{
|
||||||
|
return _info.absolutePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString File::baseName() const
|
||||||
|
{
|
||||||
|
return _info.baseName();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString File::completeBaseName() const
|
||||||
|
{
|
||||||
|
return _info.completeBaseName();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString File::suffix() const
|
||||||
|
{
|
||||||
|
return _info.suffix();
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 File::size() const
|
||||||
|
{
|
||||||
|
return _info.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList File::fitsKeywords()
|
||||||
|
{
|
||||||
|
QThread::msleep(500);
|
||||||
|
loadFitsKeywords();
|
||||||
|
return _fitsKeywords.keys();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString File::fitsValue(const QString &key)
|
||||||
|
{
|
||||||
|
loadFitsKeywords();
|
||||||
|
if(_fitsKeywords.contains(key))
|
||||||
|
return _fitsKeywords[key];
|
||||||
|
else
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::isMarked() const
|
||||||
|
{
|
||||||
|
return _engine->isMarked(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::copy(const QString &newpath) const
|
||||||
|
{
|
||||||
|
return QFile::copy(_path, _engine->outputDir() + newpath);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::move(const QString &newpath) const
|
||||||
|
{
|
||||||
|
return QFile::rename(_path, _engine->outputDir() + newpath);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool File::convertTo(const QString &format)
|
||||||
|
{
|
||||||
|
_engine->reportError("Not implemented");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScriptEngineThread::ScriptEngineThread(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
_thread = new QThread();
|
||||||
|
_thread->setObjectName("ScriptEngine");
|
||||||
|
_engine = new ScriptEngine;
|
||||||
|
_engine->moveToThread(_thread);
|
||||||
|
connect(_engine, &ScriptEngine::finished, _thread, &QThread::quit);
|
||||||
|
connect(_engine, &ScriptEngine::newMessage, this, &ScriptEngineThread::newMessage);
|
||||||
|
connect(_thread, &QThread::started, _engine, &ScriptEngine::run);
|
||||||
|
connect(_thread, &QThread::finished, _engine, &ScriptEngine::deleteLater);
|
||||||
|
connect(_thread, &QThread::finished, _thread, &QThread::deleteLater);
|
||||||
|
connect(_thread, &QThread::finished, this, &ScriptEngineThread::finished);
|
||||||
|
}
|
||||||
|
|
||||||
|
ScriptEngineThread::~ScriptEngineThread()
|
||||||
|
{
|
||||||
|
if(_engine)_engine->interrupt();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptEngineThread::setParams(const QString &scriptPath, const QStringList &paths, const QString &outputDir)
|
||||||
|
{
|
||||||
|
_engine->setParams(scriptPath, paths, outputDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptEngineThread::start()
|
||||||
|
{
|
||||||
|
_thread->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScriptEngineThread::interrupt()
|
||||||
|
{
|
||||||
|
if(_engine)_engine->interrupt();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
#ifndef SCRIPTENGINE_H
|
||||||
|
#define SCRIPTENGINE_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QJSEngine>
|
||||||
|
#include <QFileInfo>
|
||||||
|
#include <QThread>
|
||||||
|
#include "database.h"
|
||||||
|
|
||||||
|
namespace Script
|
||||||
|
{
|
||||||
|
|
||||||
|
class File;
|
||||||
|
|
||||||
|
class ScriptEngine : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
QJSEngine *_jsEngine;
|
||||||
|
Database *_database;
|
||||||
|
QString _scriptPath;
|
||||||
|
QString _outputDir;
|
||||||
|
QStringList _paths;
|
||||||
|
public:
|
||||||
|
explicit ScriptEngine(QObject *parent = nullptr);
|
||||||
|
void setParams(const QString &scriptPath, const QStringList &paths, const QString &outputDir);
|
||||||
|
void reportError(const QString &message);
|
||||||
|
const QString& outputDir() const;
|
||||||
|
void interrupt();
|
||||||
|
Q_INVOKABLE void log(const QString &message);
|
||||||
|
Q_INVOKABLE void mark(File *file);
|
||||||
|
Q_INVOKABLE void unmark(File *file);
|
||||||
|
Q_INVOKABLE bool isMarked(const File *file) const;
|
||||||
|
public slots:
|
||||||
|
void run();
|
||||||
|
signals:
|
||||||
|
void newMessage(const QString &message);
|
||||||
|
void finished();
|
||||||
|
};
|
||||||
|
|
||||||
|
class ScriptEngineThread : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
QThread *_thread;
|
||||||
|
ScriptEngine *_engine;
|
||||||
|
public:
|
||||||
|
ScriptEngineThread(QObject *parent = nullptr);
|
||||||
|
~ScriptEngineThread();
|
||||||
|
void setParams(const QString &scriptPath, const QStringList &paths, const QString &outputDir);
|
||||||
|
void start();
|
||||||
|
void interrupt();
|
||||||
|
signals:
|
||||||
|
void newMessage(const QString &message);
|
||||||
|
void finished();
|
||||||
|
};
|
||||||
|
|
||||||
|
class File : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
ScriptEngine *_engine;
|
||||||
|
QString _path;
|
||||||
|
QFileInfo _info;
|
||||||
|
bool _fitsKeywordsLoaded = false;
|
||||||
|
QMap<QString, QString> _fitsKeywords;
|
||||||
|
void loadFitsKeywords();
|
||||||
|
public:
|
||||||
|
explicit File(const QString &path, ScriptEngine *engine);
|
||||||
|
Q_INVOKABLE QString fileName() const;
|
||||||
|
Q_INVOKABLE QString absoluteFilePath() const;
|
||||||
|
Q_INVOKABLE QString absolutePath() const;
|
||||||
|
Q_INVOKABLE QString baseName() const;
|
||||||
|
Q_INVOKABLE QString completeBaseName() const;
|
||||||
|
Q_INVOKABLE QString suffix() const;
|
||||||
|
Q_INVOKABLE qint64 size() const;
|
||||||
|
Q_INVOKABLE QStringList fitsKeywords();
|
||||||
|
Q_INVOKABLE QString fitsValue(const QString &key);
|
||||||
|
Q_INVOKABLE bool isMarked() const;
|
||||||
|
Q_INVOKABLE bool copy(const QString &newpath) const;
|
||||||
|
Q_INVOKABLE bool move(const QString &newpath) const;
|
||||||
|
Q_INVOKABLE bool convertTo(const QString &format);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // SCRIPTENGINE_H
|
||||||
Reference in New Issue
Block a user