Compare commits

...

4 Commits

Author SHA1 Message Date
nou 03492972cb Include all types in completion 2025-09-14 20:44:36 +02:00
nou 9cca183677 Working copy/move operation 2025-09-14 20:44:07 +02:00
nou afd059b36b Add some margins when retriving objects 2025-09-14 13:43:20 +02:00
nou 1b9f218acb Console line with simple auto completion 2025-08-17 17:39:01 +02:00
9 changed files with 656 additions and 58 deletions
+87 -4
View File
@@ -13,6 +13,7 @@
#include <QChart> #include <QChart>
#include <QChartView> #include <QChartView>
#include <QLineSeries> #include <QLineSeries>
#include <QCompleter>
#include "scriptengine.h" #include "scriptengine.h"
#include "chartgraph.h" #include "chartgraph.h"
@@ -110,6 +111,35 @@ BatchProcessing::BatchProcessing(Database *database, QWidget *parent) : QDialog(
_textColor = _ui->log->palette().text().color(); _textColor = _ui->log->palette().text().color();
_engine = new Script::ScriptEngine(_database, this);
connect(_engine, &Script::ScriptEngine::newMessage, this, &BatchProcessing::newMessage);
QStringList apiList;
apiList << "core.log" << "core.mark" << "core.unmark" << "core.isMarked" << "core.getObjects" << "core.setMaxthread";
apiList << "core.sync" << "core.getString" << "core.getInt" << "core.getFloat" << "core.question" << "core.plot";
apiList << "fileName" << "absoluteFileName";
_completerModel = new QStringListModel(this);
_completerModel->setStringList(apiList);
_completer = new QCompleter(_completerModel, this);
_ui->consoleLineEdit->setCompleter(_completer);
connect(_ui->executeButton, &QPushButton::clicked, _ui->consoleLineEdit, &QLineEdit::returnPressed);
connect(_ui->consoleLineEdit, &QLineEdit::returnPressed, [this](){
if(!_completer->popup()->isVisible())
{
QString program = _ui->consoleLineEdit->text();
QJSValue val = _engine->eval(program);
_ui->consoleLineEdit->addLine();
qDebug() << val.toString();
}
});
connect(_ui->consoleLineEdit, &QLineEdit::textEdited, [this](const QString &text){
QStringList comp = _engine->complete(text);
qDebug() << comp;
_completerModel->setStringList(comp);
});
_ui->addFilesButton->setAutoDefault(false);
QSettings settings; QSettings settings;
_ui->outputPath->setText(settings.value("batchprocessing/outputpath", QStandardPaths::standardLocations(QStandardPaths::PicturesLocation).first()).toString()); _ui->outputPath->setText(settings.value("batchprocessing/outputpath", QStandardPaths::standardLocations(QStandardPaths::PicturesLocation).first()).toString());
} }
@@ -143,6 +173,15 @@ void BatchProcessing::closeEvent(QCloseEvent *event)
} }
} }
void BatchProcessing::refreshPaths()
{
QStringList paths;
for(int i=0; i<_ui->pathsList->count(); i++)
paths.append(_ui->pathsList->item(i)->text());
_paths = scanDirectories(paths);
_engine->setParams("", _paths, _ui->outputPath->text());
}
void BatchProcessing::addFiles() void BatchProcessing::addFiles()
{ {
QSettings settings; QSettings settings;
@@ -152,6 +191,7 @@ void BatchProcessing::addFiles()
_ui->pathsList->addItems(files); _ui->pathsList->addItems(files);
settings.setValue("batchprocessing/inputpath", QFileInfo(files.first()).absolutePath()); settings.setValue("batchprocessing/inputpath", QFileInfo(files.first()).absolutePath());
} }
refreshPaths();
} }
void BatchProcessing::addDir() void BatchProcessing::addDir()
@@ -163,6 +203,7 @@ void BatchProcessing::addDir()
_ui->pathsList->addItem(dir); _ui->pathsList->addItem(dir);
settings.setValue("batchprocessing/inputpath", dir); settings.setValue("batchprocessing/inputpath", dir);
} }
refreshPaths();
} }
void BatchProcessing::addMarked() void BatchProcessing::addMarked()
@@ -174,17 +215,20 @@ void BatchProcessing::addMarked()
if(info.exists() && info.isReadable()) if(info.exists() && info.isReadable())
_ui->pathsList->addItem(file); _ui->pathsList->addItem(file);
}; };
refreshPaths();
} }
void BatchProcessing::removePath() void BatchProcessing::removePath()
{ {
for(auto &item : _ui->pathsList->selectedItems()) for(auto &item : _ui->pathsList->selectedItems())
delete item; delete item;
refreshPaths();
} }
void BatchProcessing::removeAllPaths() void BatchProcessing::removeAllPaths()
{ {
_ui->pathsList->clear(); _ui->pathsList->clear();
refreshPaths();
} }
void BatchProcessing::browse() void BatchProcessing::browse()
@@ -208,9 +252,6 @@ void BatchProcessing::runScript()
_engineThread = new Script::ScriptEngineThread(_database, this); _engineThread = new Script::ScriptEngineThread(_database, this);
connect(_engineThread, &Script::ScriptEngineThread::newMessage, this, &BatchProcessing::newMessage); connect(_engineThread, &Script::ScriptEngineThread::newMessage, this, &BatchProcessing::newMessage);
connect(_engineThread, &Script::ScriptEngineThread::finished, this, &BatchProcessing::scriptFinished); 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()); QFileInfo outDir(_ui->outputPath->text());
if(outDir.exists() && outDir.isWritable()) if(outDir.exists() && outDir.isWritable())
@@ -221,7 +262,7 @@ void BatchProcessing::runScript()
else else
script = ":/scripts/" + script; script = ":/scripts/" + script;
_engineThread->setParams(script, scanDirectories(paths), _ui->outputPath->text()); _engineThread->setParams(script, _paths, _ui->outputPath->text());
_engineThread->start(); _engineThread->start();
_ui->startButton->setEnabled(false); _ui->startButton->setEnabled(false);
_ui->stopButton->setEnabled(true); _ui->stopButton->setEnabled(true);
@@ -329,6 +370,48 @@ void BatchProcessing::plot(const QVariant &graph)
chart->plot(graph); chart->plot(graph);
} }
ConsoleLine::ConsoleLine(QWidget *parent) : QLineEdit(parent)
{
}
void ConsoleLine::addLine()
{
QString line = text();
clear();
if(_history.size() && _history.last() == line)return;
_history.append(line);
if(_history.size() > 100)_history.removeFirst();
_currentLine = _history.size();
}
void ConsoleLine::keyReleaseEvent(QKeyEvent *event)
{
if(event->key() == Qt::Key_Up)
{
_currentLine--;
if(_currentLine < 0)
{
_currentLine = -1;
clear();
return;
}
setText(_history.at(_currentLine));
}
else if(event->key() == Qt::Key_Down)
{
_currentLine++;
if(_currentLine >= _history.size())
{
_currentLine = _history.size();
clear();
return;
}
setText(_history.at(_currentLine));
}
else QLineEdit::keyReleaseEvent(event);
}
void openDir(const QString &path) void openDir(const QString &path)
{ {
#ifdef Q_OS_LINUX #ifdef Q_OS_LINUX
+20
View File
@@ -3,6 +3,9 @@
#include <QDialog> #include <QDialog>
#include <QFileSystemWatcher> #include <QFileSystemWatcher>
#include <QStringListModel>
#include <QCompleter>
#include <QLineEdit>
#include "scriptengine.h" #include "scriptengine.h"
namespace Ui { class BatchProcessing; } namespace Ui { class BatchProcessing; }
@@ -16,8 +19,12 @@ class BatchProcessing : public QDialog
QString _scriptBasePath; QString _scriptBasePath;
QFileSystemWatcher _fileWatcher; QFileSystemWatcher _fileWatcher;
Script::ScriptEngineThread *_engineThread = nullptr; Script::ScriptEngineThread *_engineThread = nullptr;
Script::ScriptEngine *_engine = nullptr;
QColor _textColor; QColor _textColor;
Database *_database; Database *_database;
QStringListModel *_completerModel = nullptr;
QCompleter *_completer = nullptr;
QList<QPair<QString, QString>> _paths;
private slots: private slots:
void scanScriptDir(); void scanScriptDir();
public: public:
@@ -25,6 +32,7 @@ public:
~BatchProcessing(); ~BatchProcessing();
protected: protected:
void closeEvent(QCloseEvent *event); void closeEvent(QCloseEvent *event);
void refreshPaths();
public slots: public slots:
void addFiles(); void addFiles();
void addDir(); void addDir();
@@ -47,6 +55,18 @@ public slots:
void plot(const QVariant &graph); void plot(const QVariant &graph);
}; };
class ConsoleLine : public QLineEdit
{
Q_OBJECT
public:
explicit ConsoleLine(QWidget *parent = nullptr);
void addLine();
void keyReleaseEvent(QKeyEvent *event) override;
private:
int _currentLine = 0;
QStringList _history;
};
void openDir(const QString &path); void openDir(const QString &path);
#endif // BATCHPROCESSING_H #endif // BATCHPROCESSING_H
+63 -33
View File
@@ -43,6 +43,9 @@
<property name="text"> <property name="text">
<string>Add files</string> <string>Add files</string>
</property> </property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget> </widget>
</item> </item>
<item> <item>
@@ -50,6 +53,9 @@
<property name="text"> <property name="text">
<string>Add directories</string> <string>Add directories</string>
</property> </property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget> </widget>
</item> </item>
<item> <item>
@@ -57,6 +63,9 @@
<property name="text"> <property name="text">
<string>Add marked</string> <string>Add marked</string>
</property> </property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget> </widget>
</item> </item>
<item> <item>
@@ -64,6 +73,9 @@
<property name="text"> <property name="text">
<string>Remove</string> <string>Remove</string>
</property> </property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget> </widget>
</item> </item>
<item> <item>
@@ -71,6 +83,9 @@
<property name="text"> <property name="text">
<string>Remove all</string> <string>Remove all</string>
</property> </property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget> </widget>
</item> </item>
</layout> </layout>
@@ -98,6 +113,9 @@
<property name="text"> <property name="text">
<string>Browse</string> <string>Browse</string>
</property> </property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget> </widget>
</item> </item>
</layout> </layout>
@@ -129,6 +147,9 @@
<property name="text"> <property name="text">
<string>Open scripts</string> <string>Open scripts</string>
</property> </property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget> </widget>
</item> </item>
</layout> </layout>
@@ -171,23 +192,30 @@
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_4"> <layout class="QHBoxLayout" name="horizontalLayout_4">
<item> <item>
<spacer name="horizontalSpacer_2"> <widget class="ConsoleLine" name="consoleLineEdit">
<property name="orientation"> <property name="placeholderText">
<enum>Qt::Horizontal</enum> <string>Console</string>
</property> </property>
<property name="sizeHint" stdset="0"> </widget>
<size> </item>
<width>40</width> <item>
<height>20</height> <widget class="QPushButton" name="executeButton">
</size> <property name="text">
<string>Execute</string>
</property> </property>
</spacer> <property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item> </item>
<item> <item>
<widget class="QPushButton" name="startButton"> <widget class="QPushButton" name="startButton">
<property name="text"> <property name="text">
<string>Start script</string> <string>Start script</string>
</property> </property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget> </widget>
</item> </item>
<item> <item>
@@ -198,12 +226,8 @@
<property name="text"> <property name="text">
<string>Stop script</string> <string>Stop script</string>
</property> </property>
</widget> <property name="autoDefault">
</item> <bool>false</bool>
<item>
<widget class="QPushButton" name="closeButton">
<property name="text">
<string>Close</string>
</property> </property>
</widget> </widget>
</item> </item>
@@ -211,23 +235,29 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<customwidgets>
<customwidget>
<class>ConsoleLine</class>
<extends>QLineEdit</extends>
<header>batchprocessing.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>pathsList</tabstop>
<tabstop>addFilesButton</tabstop>
<tabstop>addDirButton</tabstop>
<tabstop>addMarkedButton</tabstop>
<tabstop>removeButton</tabstop>
<tabstop>removeAllButton</tabstop>
<tabstop>browseButton</tabstop>
<tabstop>openScriptsButton</tabstop>
<tabstop>scriptsList</tabstop>
<tabstop>consoleLineEdit</tabstop>
<tabstop>startButton</tabstop>
<tabstop>stopButton</tabstop>
<tabstop>outputPath</tabstop>
<tabstop>log</tabstop>
</tabstops>
<resources/> <resources/>
<connections> <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> </ui>
+319 -2
View File
@@ -5,8 +5,213 @@
#include <QSettings> #include <QSettings>
#include <QStandardPaths> #include <QStandardPaths>
#include <QDesktopServices> #include <QDesktopServices>
#include <QMimeData>
#include <QClipboard>
#include <QThread>
#include "loadimage.h" #include "loadimage.h"
class FileTimes
{
public:
explicit FileTimes(const QString &path)
{
QFile file(path);
#ifndef Q_OS_WIN
birthTime = file.fileTime(QFileDevice::FileBirthTime);
#endif
modificationTime = file.fileTime(QFileDevice::FileModificationTime);
accessTime = file.fileTime(QFileDevice::FileAccessTime);
}
void apply(const QString &path)
{
QFile file(path);
if(file.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::ExistingOnly))
{
#ifndef Q_OS_WIN // Only windows allow changing birth time
file.setFileTime(birthTime, QFileDevice::FileBirthTime);
#endif
file.setFileTime(accessTime, QFileDevice::FileAccessTime);
file.setFileTime(modificationTime, QFileDevice::FileModificationTime);
}
}
private:
QDateTime birthTime;
QDateTime modificationTime;
QDateTime accessTime;
};
FileTransfer::FileTransfer(FileManager *fm) :
_fm(fm)
{
}
FileTransfer::~FileTransfer()
{
_run = false;
}
void FileTransfer::copy(const QStringList &src, const QString &dst)
{
_run = true;
perform(src, dst, true);
emit finished();
}
void FileTransfer::move(const QStringList &src, const QString &dst)
{
_run = true;
perform(src, dst, false);
emit finished();
}
void FileTransfer::cancel()
{
_run = false;
}
void FileTransfer::perform(const QStringList &src, const QString &dst, bool copy)
{
QDir dstDir(dst);
if(!dstDir.exists())
{
emit error(tr("Error"), tr("Destination directory %1 doesn't exists").arg(dstDir.absolutePath()));
return;
}
QList<Action> actions;
QStringList dirs;
emit progress(0);
for(const QString &i : src)
{
QFileInfo srcInfo(i);
if(srcInfo.absolutePath() == dst || dst.startsWith(srcInfo.absoluteFilePath()))
return;
if(srcInfo.isDir())
{
QDir srcDir(i);
//qDebug() << "dir" << srcInfo.absoluteFilePath() << srcInfo.fileName();
if(!copy && !dstDir.exists(srcInfo.fileName()))
{
if(QFile::rename(srcInfo.absoluteFilePath(), dstDir.absoluteFilePath(srcInfo.fileName())))
continue;
}
actions.append({srcInfo.absoluteFilePath(), srcInfo.fileName(), true});
if(!copy)dirs.prepend(srcInfo.absoluteFilePath());
QDirIterator it(i, QDirIterator::Subdirectories | QDirIterator::FollowSymlinks);
while(it.hasNext())
{
QFileInfo info = it.nextFileInfo();
if(info.fileName() == "." || info.fileName() == "..")
continue;
QString relativePath = srcDir.dirName() + "/" + srcDir.relativeFilePath(info.absoluteFilePath());
if(info.isDir())
{
actions.append({"", relativePath, true});
if(!copy)dirs.prepend(info.absoluteFilePath());
//qDebug() << "dir" << info.absoluteFilePath() << relativePath;
}
else
{
actions.append({info.absoluteFilePath(), dstDir.absoluteFilePath(relativePath), false});
//qDebug() << "file" << info.absoluteFilePath() << dstDir.absoluteFilePath(relativePath);
}
}
}
else
{
actions.append({srcInfo.absoluteFilePath(), dstDir.absoluteFilePath(srcInfo.fileName())});
//qDebug() << "file" << srcInfo.absoluteFilePath() << dstDir.absoluteFilePath(srcInfo.fileName());
}
}
bool overwriteAll = false;
bool skipAll = false;
int total = actions.size();
int i = 0;
for(auto &a : actions)
{
if(!_run)
return;
if(a.dir)
{
dstDir.mkpath(a.dst);
}
else
{
QFileInfo dstInfo(a.dst);
if(dstInfo.exists())
{
if(overwriteAll)
{
QFile::remove(dstInfo.absoluteFilePath());
}
else if(skipAll)
{
emit progress(i++ * 100 / total);
continue;
}
else
{
QMessageBox::StandardButton ret;
QMetaObject::invokeMethod(_fm, "overwrite", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QMessageBox::StandardButton, ret), Q_ARG(QString, dstInfo.fileName()));
switch(ret)
{
case QMessageBox::YesToAll:
overwriteAll = true;//break; is intentionally missing
case QMessageBox::Yes:
QFile::remove(dstInfo.absoluteFilePath());
break;
case QMessageBox::NoToAll:
skipAll = true;//break; is intentionally missing
case QMessageBox::No:
emit progress(i++ * 100 / total);
continue;
break;
case QMessageBox::Cancel:
return;
default:
break;
}
}
}
FileTimes t(a.src);
if(copy)
{
if(!QFile::copy(a.src, a.dst))
{
emit error(tr("Copy failed"), tr("Failed to copy file %1 to %2").arg(a.src).arg(a.dst));
return;
}
}
else
{
if(!QFile::rename(a.src, a.dst))
{
emit error(tr("Move failed"), tr("Failed to move file %1 to %2").arg(a.src).arg(a.dst));
return;
}
}
t.apply(a.dst);
}
emit progress(i++ * 100 / total);
}
if(!copy)
{
for(const QString &d : dirs)
{
QDir dir(d);
if(dir.isEmpty())
dir.removeRecursively();
}
}
}
PathTabBar::PathTabBar(const QStringList &tabs) : PathTabBar::PathTabBar(const QStringList &tabs) :
_tabs(tabs) _tabs(tabs)
{ {
@@ -147,6 +352,8 @@ FileManager::FileManager(const QSet<QString> &openFilter, QWidget *parent) : QMa
connect(ui->rightTab, &DirView::dirChanged, _rightTabBar, &PathTabBar::pathChanged); connect(ui->rightTab, &DirView::dirChanged, _rightTabBar, &PathTabBar::pathChanged);
connect(ui->leftTab, &DirView::openFile, this, &FileManager::openFile); connect(ui->leftTab, &DirView::openFile, this, &FileManager::openFile);
connect(ui->rightTab, &DirView::openFile, this, &FileManager::openFile); connect(ui->rightTab, &DirView::openFile, this, &FileManager::openFile);
connect(ui->leftTab, &DirView::filesAction, this, &FileManager::copyMoveFiles, Qt::QueuedConnection);
connect(ui->rightTab, &DirView::filesAction, this, &FileManager::copyMoveFiles, Qt::QueuedConnection);
connect(ui->actionLoad_FITS_keywordsLeft, &QAction::toggled, ui->leftTab, &DirView::loadFitsKeywords); connect(ui->actionLoad_FITS_keywordsLeft, &QAction::toggled, ui->leftTab, &DirView::loadFitsKeywords);
connect(ui->actionLoad_FITS_keywordsRight, &QAction::toggled, ui->rightTab, &DirView::loadFitsKeywords); connect(ui->actionLoad_FITS_keywordsRight, &QAction::toggled, ui->rightTab, &DirView::loadFitsKeywords);
@@ -165,6 +372,8 @@ FileManager::FileManager(const QSet<QString> &openFilter, QWidget *parent) : QMa
connect(ui->actionSelect_columnsLeft, &QAction::triggered, this, &FileManager::selectFITSKeywords); connect(ui->actionSelect_columnsLeft, &QAction::triggered, this, &FileManager::selectFITSKeywords);
connect(ui->actionSelect_columnsRight, &QAction::triggered, this, &FileManager::selectFITSKeywords); connect(ui->actionSelect_columnsRight, &QAction::triggered, this, &FileManager::selectFITSKeywords);
connect(ui->actionCopySelectedFilesPathsLeft, &QAction::triggered, this, &FileManager::copySelectedFilesPaths);
connect(ui->actionCopySelectedFilesPathsRight, &QAction::triggered, this, &FileManager::copySelectedFilesPaths);
connect(ui->leftPath, &QLineEdit::returnPressed, this, &FileManager::pathEdited); connect(ui->leftPath, &QLineEdit::returnPressed, this, &FileManager::pathEdited);
connect(ui->rightPath, &QLineEdit::returnPressed, this, &FileManager::pathEdited); connect(ui->rightPath, &QLineEdit::returnPressed, this, &FileManager::pathEdited);
@@ -175,6 +384,25 @@ FileManager::FileManager(const QSet<QString> &openFilter, QWidget *parent) : QMa
ui->menuLeft_Tab->addAction(drive.absoluteFilePath(), [path, this](){ ui->leftTab->setDir(path); }); ui->menuLeft_Tab->addAction(drive.absoluteFilePath(), [path, this](){ ui->leftTab->setDir(path); });
ui->menuRight_Tab->addAction(drive.absoluteFilePath(), [path, this](){ ui->rightTab->setDir(path); }); ui->menuRight_Tab->addAction(drive.absoluteFilePath(), [path, this](){ ui->rightTab->setDir(path); });
} }
ui->progressBar->hide();
ui->cancelButton->hide();
_thread = new QThread(this);
_thread->start();
_fileTransfer = new FileTransfer(this);
_fileTransfer->moveToThread(_thread);
connect(_fileTransfer, &FileTransfer::progress, ui->progressBar, &QProgressBar::setValue);
connect(_fileTransfer, &FileTransfer::error, this, &FileManager::errorMessage);
connect(_fileTransfer, &FileTransfer::finished, [this](){
ui->leftTab->setDragEnabled(true);
ui->rightTab->setDragEnabled(true);
ui->progressBar->hide();
ui->cancelButton->hide();
});
connect(this, &FileManager::copy, _fileTransfer, &FileTransfer::copy);
connect(this, &FileManager::move, _fileTransfer, &FileTransfer::move);
connect(ui->cancelButton, &QPushButton::clicked, [this](){ _fileTransfer->cancel(); });
} }
FileManager::~FileManager() FileManager::~FileManager()
@@ -190,6 +418,12 @@ FileManager::~FileManager()
settings.setValue("filemanager/rightLoadFitsKeywords", ui->actionLoad_FITS_keywordsRight->isChecked()); settings.setValue("filemanager/rightLoadFitsKeywords", ui->actionLoad_FITS_keywordsRight->isChecked());
settings.setValue("filemanager/geometry", saveGeometry()); settings.setValue("filemanager/geometry", saveGeometry());
delete ui; delete ui;
_fileTransfer->cancel();
_thread->quit();
_thread->wait();
delete _fileTransfer;
} }
void FileManager::selectFITSKeywords() void FileManager::selectFITSKeywords()
@@ -213,6 +447,14 @@ void FileManager::selectFITSKeywords()
} }
} }
void FileManager::copySelectedFilesPaths()
{
if(sender() == ui->actionCopySelectedFilesPathsLeft)
ui->leftTab->copySelectedFilesPathsToClipboard();
if(sender() == ui->actionCopySelectedFilesPathsRight)
ui->rightTab->copySelectedFilesPathsToClipboard();
}
void FileManager::pathEdited() void FileManager::pathEdited()
{ {
if(sender() == ui->leftPath) if(sender() == ui->leftPath)
@@ -229,6 +471,40 @@ void FileManager::pathEdited()
} }
} }
void FileManager::copyMoveFiles(Qt::DropAction action, const QStringList &src, const QString &dst)
{
ui->leftTab->setDragEnabled(false);
ui->rightTab->setDragEnabled(false);
ui->progressBar->show();
ui->cancelButton->show();
switch(action)
{
case Qt::CopyAction:
emit copy(src, dst);
break;
case Qt::MoveAction:
emit move(src, dst);
break;
case Qt::LinkAction:
default:
break;
}
}
QMessageBox::StandardButton FileManager::overwrite(const QString &dst)
{
QMessageBox::StandardButton button = QMessageBox::question(this, tr("Overwrite file?"), tr("Destination file %1 already exists. Overwrite?").arg(dst),
QMessageBox::Yes | QMessageBox::YesToAll | QMessageBox::No | QMessageBox::NoToAll | QMessageBox::Cancel);
return button;
}
void FileManager::errorMessage(const QString &title, const QString &text)
{
QMessageBox::critical(this, title, text);
}
QCache<QString, ImageInfoData>* DirFileSystemModel::getCacheInstance() QCache<QString, ImageInfoData>* DirFileSystemModel::getCacheInstance()
{ {
static bool init = true; static bool init = true;
@@ -241,7 +517,8 @@ QCache<QString, ImageInfoData>* DirFileSystemModel::getCacheInstance()
return &cache; return &cache;
} }
DirFileSystemModel::DirFileSystemModel(QObject *parent) : QFileSystemModel(parent) DirFileSystemModel::DirFileSystemModel(QWidget *parentWidget) : QFileSystemModel(parentWidget)
,_parentWidget(parentWidget)
{ {
_cache = getCacheInstance(); _cache = getCacheInstance();
setFilter(QDir::AllEntries | QDir::NoDot); setFilter(QDir::AllEntries | QDir::NoDot);
@@ -272,7 +549,9 @@ const QStringList &DirFileSystemModel::FITSKeywords() const
Qt::ItemFlags DirFileSystemModel::flags(const QModelIndex &index) const Qt::ItemFlags DirFileSystemModel::flags(const QModelIndex &index) const
{ {
return QFileSystemModel::flags(index) & ~Qt::ItemIsEditable; Qt::ItemFlags ret = QFileSystemModel::flags(index) & ~Qt::ItemIsEditable;
if(index.row() == 0)ret &= ~Qt::ItemIsDragEnabled;
return ret;
} }
int DirFileSystemModel::columnCount(const QModelIndex &parent) const int DirFileSystemModel::columnCount(const QModelIndex &parent) const
@@ -335,6 +614,21 @@ bool DirFileSystemModel::hasChildren(const QModelIndex &parent) const
return QFileSystemModel::hasChildren(parent); return QFileSystemModel::hasChildren(parent);
} }
bool DirFileSystemModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
{
Q_UNUSED(row);
Q_UNUSED(column);
if(data->hasUrls())
{
QStringList srcPaths;
for(auto &url : data->urls())
srcPaths.append(url.toLocalFile());
emit filesAction(action, srcPaths, filePath(parent));
}
return false;
}
void DirFileSystemModel::loadFitsKeywords(bool enable) void DirFileSystemModel::loadFitsKeywords(bool enable)
{ {
_loadFitsKeywords = enable; _loadFitsKeywords = enable;
@@ -348,6 +642,8 @@ DirView::DirView(QWidget *parent) : QTreeView(parent)
setDragEnabled(true); setDragEnabled(true);
setAcceptDrops(true); setAcceptDrops(true);
connect(_dirFileSystemModel, &DirFileSystemModel::filesAction, this, &DirView::filesAction);
setModel(_dirFileSystemModel); setModel(_dirFileSystemModel);
setSelectionMode(QAbstractItemView::ExtendedSelection); setSelectionMode(QAbstractItemView::ExtendedSelection);
@@ -435,3 +731,24 @@ void DirView::loadFitsKeywords(bool enable)
{ {
_dirFileSystemModel->loadFitsKeywords(enable); _dirFileSystemModel->loadFitsKeywords(enable);
} }
void DirView::copySelectedFilesPathsToClipboard() const
{
QList<QUrl> urls;
QString text;
auto selected = selectionModel()->selectedRows();
for(auto &item : selected)
{
if(item.column() == 0)
{
QString path = _dirFileSystemModel->filePath(item);
text.append(path); text.append('\n');
urls.append(QUrl::fromLocalFile(path));
}
}
QClipboard *clipboard = QApplication::clipboard();
QMimeData *mimeData = new QMimeData();
mimeData->setUrls(urls);
mimeData->setText(text);
clipboard->setMimeData(mimeData);
}
+50 -6
View File
@@ -8,6 +8,7 @@
#include <QDialog> #include <QDialog>
#include <QTabBar> #include <QTabBar>
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QMessageBox>
#include "imageinfodata.h" #include "imageinfodata.h"
namespace Ui { namespace Ui {
@@ -15,6 +16,34 @@ class FileManager;
class FITSKeyword; class FITSKeyword;
} }
class FileManager;
class FileTransfer: public QObject
{
Q_OBJECT
public:
explicit FileTransfer(FileManager *fm);
~FileTransfer();
public slots:
void copy(const QStringList &src, const QString &dst);
void move(const QStringList &src, const QString &dst);
void cancel();
signals:
void progress(int percent);
void finished();
void error(const QString &title, const QString &text);
private:
void perform(const QStringList &src, const QString &dst, bool copy);
struct Action
{
QString src;
QString dst;
bool dir = false;
};
FileManager *_fm;
bool _run = true;
};
class PathTabBar : public QTabBar class PathTabBar : public QTabBar
{ {
Q_OBJECT Q_OBJECT
@@ -51,25 +80,28 @@ public:
~FileManager(); ~FileManager();
public slots: public slots:
void selectFITSKeywords(); void selectFITSKeywords();
void copySelectedFilesPaths();
void pathEdited(); void pathEdited();
void copyMoveFiles(Qt::DropAction action, const QStringList &src, const QString &dst);
QMessageBox::StandardButton overwrite(const QString &dst);
void errorMessage(const QString &title, const QString &text);
signals: signals:
void openFile(const QString &path); void openFile(const QString &path);
void copy(const QStringList &src, const QString &dst);
void move(const QStringList &src, const QString &dst);
private: private:
Ui::FileManager *ui; Ui::FileManager *ui;
PathTabBar *_leftTabBar; PathTabBar *_leftTabBar;
PathTabBar *_rightTabBar; PathTabBar *_rightTabBar;
QThread *_thread;
FileTransfer *_fileTransfer;
}; };
class DirFileSystemModel : public QFileSystemModel class DirFileSystemModel : public QFileSystemModel
{ {
Q_OBJECT Q_OBJECT
mutable QCache<QString, ImageInfoData> *_cache = nullptr;
static QCache<QString, ImageInfoData>* getCacheInstance();
QModelIndex _dir;
QStringList _fitsKeywords;
bool _loadFitsKeywords = true;
public: public:
explicit DirFileSystemModel(QObject *parent = nullptr); explicit DirFileSystemModel(QWidget *parentWidget);
void setDir(const QString &path); void setDir(const QString &path);
QString dir() const; QString dir() const;
void setFITSKeywords(const QStringList &keywords); void setFITSKeywords(const QStringList &keywords);
@@ -79,8 +111,18 @@ public:
QVariant data(const QModelIndex &index, int role) const override; QVariant data(const QModelIndex &index, int role) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override; QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
bool hasChildren(const QModelIndex &parent) const override; bool hasChildren(const QModelIndex &parent) const override;
bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override;
public slots: public slots:
void loadFitsKeywords(bool enable); void loadFitsKeywords(bool enable);
signals:
void filesAction(Qt::DropAction action, const QStringList &src, const QString &dst);
private:
mutable QCache<QString, ImageInfoData> *_cache = nullptr;
static QCache<QString, ImageInfoData>* getCacheInstance();
QModelIndex _dir;
QStringList _fitsKeywords;
bool _loadFitsKeywords = true;
QWidget *_parentWidget = nullptr;
}; };
class DirView : public QTreeView class DirView : public QTreeView
@@ -98,9 +140,11 @@ public:
public slots: public slots:
void headerContextMenu(const QPoint &pos); void headerContextMenu(const QPoint &pos);
void loadFitsKeywords(bool enable); void loadFitsKeywords(bool enable);
void copySelectedFilesPathsToClipboard() const;
signals: signals:
void dirChanged(const QString &path); void dirChanged(const QString &path);
void openFile(const QString &path); void openFile(const QString &path);
void filesAction(Qt::DropAction action, const QStringList &src, const QString &dst);
}; };
#endif // FILEMANAGER_H #endif // FILEMANAGER_H
+47 -7
View File
@@ -14,24 +14,52 @@
<string>File Manager</string> <string>File Manager</string>
</property> </property>
<widget class="QWidget" name="centralwidget"> <widget class="QWidget" name="centralwidget">
<layout class="QHBoxLayout" name="horizontalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<item> <item>
<layout class="QVBoxLayout" name="leftLayout"> <layout class="QHBoxLayout" name="horizontalLayout">
<item> <item>
<widget class="QLineEdit" name="leftPath"/> <layout class="QVBoxLayout" name="leftLayout">
<item>
<widget class="QLineEdit" name="leftPath"/>
</item>
<item>
<widget class="DirView" name="leftTab"/>
</item>
</layout>
</item> </item>
<item> <item>
<widget class="DirView" name="leftTab"/> <layout class="QVBoxLayout" name="rightLayout">
<item>
<widget class="QLineEdit" name="rightPath"/>
</item>
<item>
<widget class="DirView" name="rightTab"/>
</item>
</layout>
</item> </item>
</layout> </layout>
</item> </item>
<item> <item>
<layout class="QVBoxLayout" name="rightLayout"> <layout class="QHBoxLayout" name="progressLayout">
<item> <item>
<widget class="QLineEdit" name="rightPath"/> <widget class="QProgressBar" name="progressBar">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="value">
<number>0</number>
</property>
</widget>
</item> </item>
<item> <item>
<widget class="DirView" name="rightTab"/> <widget class="QPushButton" name="cancelButton">
<property name="text">
<string>Cancel</string>
</property>
</widget>
</item> </item>
</layout> </layout>
</item> </item>
@@ -52,6 +80,7 @@
</property> </property>
<addaction name="actionLoad_FITS_keywordsLeft"/> <addaction name="actionLoad_FITS_keywordsLeft"/>
<addaction name="actionSelect_columnsLeft"/> <addaction name="actionSelect_columnsLeft"/>
<addaction name="actionCopySelectedFilesPathsLeft"/>
<addaction name="separator"/> <addaction name="separator"/>
</widget> </widget>
<widget class="QMenu" name="menuRight_Tab"> <widget class="QMenu" name="menuRight_Tab">
@@ -60,6 +89,7 @@
</property> </property>
<addaction name="actionLoad_FITS_keywordsRight"/> <addaction name="actionLoad_FITS_keywordsRight"/>
<addaction name="actionSelect_columnsRight"/> <addaction name="actionSelect_columnsRight"/>
<addaction name="actionCopySelectedFilesPathsRight"/>
<addaction name="separator"/> <addaction name="separator"/>
</widget> </widget>
<addaction name="menuLeft_Tab"/> <addaction name="menuLeft_Tab"/>
@@ -97,6 +127,16 @@
<string>Select columns</string> <string>Select columns</string>
</property> </property>
</action> </action>
<action name="actionCopySelectedFilesPathsLeft">
<property name="text">
<string>Copy selected files paths</string>
</property>
</action>
<action name="actionCopySelectedFilesPathsRight">
<property name="text">
<string>Copy selected files paths</string>
</property>
</action>
</widget> </widget>
<customwidgets> <customwidgets>
<customwidget> <customwidget>
+2 -1
View File
@@ -453,7 +453,8 @@ SkyGrid WCSDataT::prepareGrid(uint32_t w, uint32_t h, Database *database)
if(database) if(database)
{ {
skyGrid.objects = database->getObjects(minRa, maxRa, minDec, maxDec); double size = std::max(maxRa - minRa, maxDec - minDec);
skyGrid.objects = database->getObjects(minRa - size, maxRa + size, minDec - size, maxDec + size);
for(auto &object : skyGrid.objects) for(auto &object : skyGrid.objects)
{ {
QPointF p; QPointF p;
+65 -5
View File
@@ -4,6 +4,7 @@
#include <QDebug> #include <QDebug>
#include <QInputDialog> #include <QInputDialog>
#include <QJsonValue> #include <QJsonValue>
#include <QJSValueIterator>
#include "loadrunable.h" #include "loadrunable.h"
#include "rawimage.h" #include "rawimage.h"
#include "loadimage.h" #include "loadimage.h"
@@ -40,7 +41,7 @@ ScriptEngine::ScriptEngine(Database *database, BatchProcessing *parent)
void ScriptEngine::setParams(const QString &scriptPath, const QList<QPair<QString, QString>> &paths, const QString &outputDir) void ScriptEngine::setParams(const QString &scriptPath, const QList<QPair<QString, QString>> &paths, const QString &outputDir)
{ {
_scriptPath = scriptPath; _scriptPath = scriptPath;
_paths = paths; setPaths(paths);
_outputDir = outputDir + "/"; _outputDir = outputDir + "/";
} }
@@ -417,14 +418,73 @@ QJSValue ScriptEngine::newArray(uint size)
return _jsEngine->newArray(size); return _jsEngine->newArray(size);
} }
void ScriptEngine::run() QJSValue ScriptEngine::eval(const QString &program)
{ {
QJSValue jsPaths = _jsEngine->newArray(_paths.size()); QStringList stackTrace;
for(qsizetype i=0; i<_paths.size(); i++) QJSValue result = _jsEngine->evaluate(program, QString(), 1, &stackTrace);
jsPaths.setProperty(i, _jsEngine->newQObject(new File(_paths[i].first, _paths[i].second, this)));
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, true);
}
else if(!result.isUndefined())
{
emit newMessage(result.toString(), false);
}
return result;
}
QStringList ScriptEngine::complete(const QString &line)
{
QStringList complete;
QJSValue globObj = _jsEngine->globalObject();
QRegularExpression reg("[a-zA-Z_][a-zA-Z0-9_]*");
auto match = reg.match(line);
if(match.hasMatch())
{
QString var = match.captured();
if(globObj.hasProperty(var))
{
complete.clear();
QJSValueIterator it(globObj.property(var));
while(it.hasNext())
{
it.next();
if(it.name() != "constructor" && it.name() != "objectNameChanged")
complete.append(var + "." + it.name());
}
}
}
else
{
QJSValueIterator it(globObj);
while(it.hasNext())
{
it.next();
complete.append(it.name());
}
}
return complete;
}
void ScriptEngine::setPaths(const QList<QPair<QString, QString> > &paths)
{
_paths = paths;
QJSValue jsPaths = _jsEngine->newArray(paths.size());
for(qsizetype i=0; i<paths.size(); i++)
jsPaths.setProperty(i, _jsEngine->newQObject(new File(paths[i].first, paths[i].second, this)));
_jsEngine->globalObject().setProperty("files", jsPaths); _jsEngine->globalObject().setProperty("files", jsPaths);
}
void ScriptEngine::run()
{
QFile scriptFile(_scriptPath); QFile scriptFile(_scriptPath);
if(!scriptFile.open(QIODevice::ReadOnly)) if(!scriptFile.open(QIODevice::ReadOnly))
{ {
+3
View File
@@ -64,6 +64,9 @@ public:
#endif // PLATESOLVER #endif // PLATESOLVER
QJSValue newObject(); QJSValue newObject();
QJSValue newArray(uint size); QJSValue newArray(uint size);
QJSValue eval(const QString &program);
QStringList complete(const QString &line);
void setPaths(const QList<QPair<QString, QString>> &paths);
public slots: public slots:
void run(); void run();
signals: signals: