Compare commits

..

3 Commits

Author SHA1 Message Date
nou f9f005e7ea Another test 2025-07-16 23:17:22 +02:00
nou 5ba6b4863c Fix metainfo linter 2025-07-16 09:07:08 +02:00
nou 6c7e078340 Testing filetree crash on ARM 2025-07-16 07:44:19 +02:00
21 changed files with 51 additions and 930 deletions
+1 -3
View File
@@ -34,9 +34,7 @@ set(TENMON_SRC
src/database.cpp src/database.h
src/databaseview.cpp src/databaseview.h
src/delete.cpp
src/filemanager.h src/filemanager.cpp src/filemanager.ui
src/filesystemwidget.cpp src/filesystemwidget.h
src/fitskeyword.ui
src/histogram.cpp src/histogram.h
src/httpdownloader.h src/httpdownloader.cpp
src/imageinfo.cpp src/imageinfo.h
@@ -79,7 +77,7 @@ endif()
qt_add_executable(tenmon WIN32 MACOSX_BUNDLE ${tenmon_ICON} ${TENMON_SRC})
find_path(FITS_INCLUDE fitsio2.h PATH_SUFFIXES cfitsio REQUIRED)
target_include_directories(tenmon PRIVATE ${FITS_INCLUDE} ${CMAKE_BINARY_DIR} ${libXISF_SOURCE_DIR} "src")
target_include_directories(tenmon PRIVATE ${FITS_INCLUDE} ${CMAKE_BINARY_DIR} ${libXISF_SOURCE_DIR})
option(COLOR_MANAGMENT "Enable sRGB framebuffer support for gamma correct images and color profiles support" ON)
if(COLOR_MANAGMENT)
+1 -1
Submodule libXISF updated: c6581e1122...9a32138f6a
+8 -24
View File
@@ -181,7 +181,7 @@ int Database::checkVersion(QSqlDatabase &db)
return -1;
}
static QStringList nameFilters = {"*.fit", "*.fits", "*.fz", "*.fts", "*.xisf"};
static QStringList nameFilters = {"*.fit", "*.fits", "*.fz", "*.xisf"};
static int countFiles(const QDir &dir, QStringList &scannedDirs)
{
@@ -271,30 +271,15 @@ QVector<SkyObject> Database::getObjects(double minRa, double maxRa, double minDe
while(m_getNgc.next())
{
QString name;
QString name2;
QString m = m_getNgc.value("M").toString();
QString ic = m_getNgc.value("IC").toString();
if(!m.isEmpty())
{
name = "M" + m;
m.clear();
}
else if(!ic.isEmpty())
{
name = "IC" + ic;
ic.clear();
}
else
{
name = m_getNgc.value("Name").toString();
}
if(!ic.isEmpty())name2 += "IC" + ic + " ";
name2 += m_getNgc.value("Common names").toString();
if(!m.isEmpty())name = "M" + m + " ";
if(!ic.isEmpty())name += "IC" + ic + " ";
name += m_getNgc.value("Name").toString();
objects.append({
name,
name2,
m_getNgc.value("Common names").toString(),
{m_getNgc.value("RA_deg").toDouble(), m_getNgc.value("DEC_deg").toDouble()},
m_getNgc.value("MajAx").toDouble(),
m_getNgc.value("MinAx").toDouble(),
@@ -347,10 +332,10 @@ bool Database::indexFile(const QFileInfo &file)
}
}
bool ok = false;
if(isXISF(file.suffix()))
bool ok;
if(filePath.endsWith(".xisf", Qt::CaseInsensitive))
ok = readXISFHeader(filePath, info);
else if(isFITS(file.suffix()))
else
ok = readFITSHeader(filePath, info);
qlonglong last_id = -1;
@@ -391,7 +376,6 @@ bool Database::indexFile(const QFileInfo &file)
QVariantList file_id, keys, values, comments;
for(const auto &record : info.fitsHeader)
{
if(record.xisf && record.key.startsWith("PCL:"))continue;
file_id << last_id;
keys << QString(record.key);
values << record.value.toString();
-437
View File
@@ -1,437 +0,0 @@
#include "filemanager.h"
#include "ui_filemanager.h"
#include "ui_fitskeyword.h"
#include <QSettings>
#include <QStandardPaths>
#include <QDesktopServices>
#include "loadimage.h"
PathTabBar::PathTabBar(const QStringList &tabs) :
_tabs(tabs)
{
setTabsClosable(true);
setExpanding(false);
for(auto &t : _tabs)
{
QDir dir(t);
int i = addTab(tabName(t));
setTabToolTip(i, t);
}
connect(this, &QTabBar::currentChanged, [this](int index){
QString path = _tabs.at(index);
emit pathChanged(path);
});
connect(this, &QTabBar::tabCloseRequested, [this](int index){
if(_tabs.size() >= 2)
{
_tabs.remove(index);
removeTab(index);
}
});
connect(this, &QTabBar::currentChanged, [this](int index){
emit tabChanged(_tabs[index]);
});
}
QHBoxLayout *PathTabBar::createLayout()
{
QHBoxLayout *hlayout = new QHBoxLayout();
hlayout->addWidget(this);
hlayout->addStretch(2);
QPushButton *addButton = new QPushButton("+");
connect(addButton, &QPushButton::clicked, [this](){
QString path = _tabs[currentIndex()];
_tabs.append(path);
int i = addTab(tabName(path));
setTabToolTip(i, path);
});
hlayout->addWidget(addButton);
return hlayout;
}
const QStringList &PathTabBar::tabPaths() const
{
return _tabs;
}
QString PathTabBar::currentTabPath() const
{
int index = std::clamp(currentIndex(), 0, (int)_tabs.size());
return _tabs[index];
}
void PathTabBar::pathChanged(const QString &path)
{
QDir dir(path);
int index = currentIndex();
setTabText(index, tabName(path));
setTabToolTip(index, path);
_tabs[index] = path;
}
QString PathTabBar::tabName(const QString &path)
{
QDir dir(path);
if(dir.dirName().isEmpty())
return path;
else
return dir.dirName();
}
FITSSelection::FITSSelection(const QStringList &keywords, QWidget *parent) : QDialog(parent)
,ui(new Ui::FITSKeyword)
{
ui->setupUi(this);
connect(ui->addButton, &QPushButton::clicked, [this](){
auto item = ui->keywordList->findItems(ui->keyword->text(), Qt::MatchFixedString | Qt::MatchCaseSensitive);
if(item.size())return;
ui->keywordList->addItem(ui->keyword->text());
});
connect(ui->removeButton, &QPushButton::clicked, [this](){
auto items = ui->keywordList->selectedItems();
for(auto item : items)
delete item;
});
ui->keywordList->addItems(keywords);
}
FITSSelection::~FITSSelection()
{
delete ui;
}
QStringList FITSSelection::FITSKeywords() const
{
QStringList keywords;
for(int i = 0; i < ui->keywordList->count(); i++)
keywords.append(ui->keywordList->item(i)->text());
return keywords;
}
FileManager::FileManager(const QSet<QString> &openFilter, QWidget *parent) : QMainWindow(parent)
,ui(new Ui::FileManager)
{
ui->setupUi(this);
QStringList standardLocations = QStandardPaths::standardLocations(QStandardPaths::PicturesLocation);
QString picturesPath;
if(standardLocations.size())
picturesPath = standardLocations.first();
QSettings settings;
QStringList leftTabs = settings.value("filemanager/leftTabPaths", picturesPath).toStringList();
QStringList rightTabs = settings.value("filemanager/rightTabPaths", picturesPath).toStringList();
if(leftTabs.empty())leftTabs.append(picturesPath);
if(rightTabs.empty())rightTabs.append(picturesPath);
ui->leftTab->setOpenFilter(openFilter);
ui->rightTab->setOpenFilter(openFilter);
_rightTabBar = new PathTabBar(rightTabs);
ui->rightLayout->insertLayout(0, _rightTabBar->createLayout());
connect(_rightTabBar, &PathTabBar::tabChanged, ui->rightTab, &DirView::setDir);
_leftTabBar = new PathTabBar(leftTabs);
ui->leftLayout->insertLayout(0, _leftTabBar->createLayout());
connect(_leftTabBar, &PathTabBar::tabChanged, ui->leftTab, &DirView::setDir);
connect(ui->leftTab, &DirView::dirChanged, ui->leftPath, &QLineEdit::setText);
connect(ui->leftTab, &DirView::dirChanged, _leftTabBar, &PathTabBar::pathChanged);
connect(ui->rightTab, &DirView::dirChanged, ui->rightPath, &QLineEdit::setText);
connect(ui->rightTab, &DirView::dirChanged, _rightTabBar, &PathTabBar::pathChanged);
connect(ui->leftTab, &DirView::openFile, this, &FileManager::openFile);
connect(ui->rightTab, &DirView::openFile, this, &FileManager::openFile);
connect(ui->actionLoad_FITS_keywordsLeft, &QAction::toggled, ui->leftTab, &DirView::loadFitsKeywords);
connect(ui->actionLoad_FITS_keywordsRight, &QAction::toggled, ui->rightTab, &DirView::loadFitsKeywords);
ui->leftTab->setDir(_leftTabBar->currentTabPath());
ui->leftTab->setFITSKeywords(settings.value("filemanager/leftFitsKeywords", QStringList("OBJECT")).toStringList());
ui->leftTab->header()->restoreState(settings.value("filemanager/leftTabHeader").toByteArray());
ui->rightTab->setDir(_rightTabBar->currentTabPath());
ui->rightTab->setFITSKeywords(settings.value("filemanager/rightFitsKeywords", QStringList("OBJECT")).toStringList());
ui->rightTab->header()->restoreState(settings.value("filemanager/rightTabHeader").toByteArray());
ui->actionLoad_FITS_keywordsLeft->setChecked(settings.value("filemanager/leftLoadFitsKeywords", true).toBool());
ui->actionLoad_FITS_keywordsRight->setChecked(settings.value("filemanager/rightLoadFitsKeywords", true).toBool());
restoreGeometry(settings.value("filemanager/geometry").toByteArray());
setAttribute(Qt::WA_DeleteOnClose);
connect(ui->actionSelect_columnsLeft, &QAction::triggered, this, &FileManager::selectFITSKeywords);
connect(ui->actionSelect_columnsRight, &QAction::triggered, this, &FileManager::selectFITSKeywords);
connect(ui->leftPath, &QLineEdit::returnPressed, this, &FileManager::pathEdited);
connect(ui->rightPath, &QLineEdit::returnPressed, this, &FileManager::pathEdited);
QFileInfoList drives = QDir::drives();
for(auto &drive : drives)
{
QString path = drive.absoluteFilePath();
ui->menuLeft_Tab->addAction(drive.absoluteFilePath(), [path, this](){ ui->leftTab->setDir(path); });
ui->menuRight_Tab->addAction(drive.absoluteFilePath(), [path, this](){ ui->rightTab->setDir(path); });
}
}
FileManager::~FileManager()
{
QSettings settings;
settings.setValue("filemanager/leftFitsKeywords", ui->leftTab->FITSKeywords());
settings.setValue("filemanager/leftTabPaths", _leftTabBar->tabPaths());
settings.setValue("filemanager/leftTabHeader", ui->leftTab->header()->saveState());
settings.setValue("filemanager/rightFitsKeywords", ui->rightTab->FITSKeywords());
settings.setValue("filemanager/rightTabPaths", _rightTabBar->tabPaths());
settings.setValue("filemanager/rightTabHeader", ui->rightTab->header()->saveState());
settings.setValue("filemanager/leftLoadFitsKeywords", ui->actionLoad_FITS_keywordsLeft->isChecked());
settings.setValue("filemanager/rightLoadFitsKeywords", ui->actionLoad_FITS_keywordsRight->isChecked());
settings.setValue("filemanager/geometry", saveGeometry());
delete ui;
}
void FileManager::selectFITSKeywords()
{
QStringList columns;
if(sender() == ui->actionSelect_columnsLeft)
columns = ui->leftTab->FITSKeywords();
if(sender() == ui->actionSelect_columnsRight)
columns = ui->rightTab->FITSKeywords();
FITSSelection selection(columns, this);
int ret = selection.exec();
if(ret == QDialog::Accepted)
{
if(sender() == ui->actionSelect_columnsLeft)
ui->leftTab->setFITSKeywords(selection.FITSKeywords());
if(sender() == ui->actionSelect_columnsRight)
ui->rightTab->setFITSKeywords(selection.FITSKeywords());
}
}
void FileManager::pathEdited()
{
if(sender() == ui->leftPath)
{
QDir dir(ui->leftPath->text());
if(dir.exists())
ui->leftTab->setDir(dir.absolutePath());
}
if(sender() == ui->rightPath)
{
QDir dir(ui->rightPath->text());
if(dir.exists())
ui->rightTab->setDir(dir.absolutePath());
}
}
QCache<QString, ImageInfoData>* DirFileSystemModel::getCacheInstance()
{
static bool init = true;
static QCache<QString, ImageInfoData> cache;
if(!init)
{
cache.setMaxCost(10000);
init = false;
}
return &cache;
}
DirFileSystemModel::DirFileSystemModel(QObject *parent) : QFileSystemModel(parent)
{
_cache = getCacheInstance();
setFilter(QDir::AllEntries | QDir::NoDot);
_fitsKeywords = {"OBJECT"};
}
void DirFileSystemModel::setDir(const QString &path)
{
_dir = index(path);
}
QString DirFileSystemModel::dir() const
{
return fileInfo(_dir).canonicalFilePath();
}
void DirFileSystemModel::setFITSKeywords(const QStringList &keywords)
{
beginResetModel();
_fitsKeywords = keywords;
endResetModel();
}
const QStringList &DirFileSystemModel::FITSKeywords() const
{
return _fitsKeywords;
}
Qt::ItemFlags DirFileSystemModel::flags(const QModelIndex &index) const
{
return QFileSystemModel::flags(index) & ~Qt::ItemIsEditable;
}
int DirFileSystemModel::columnCount(const QModelIndex &parent) const
{
return QFileSystemModel::columnCount(parent) + _fitsKeywords.size();
}
QVariant DirFileSystemModel::data(const QModelIndex &index, int role) const
{
if(index.column() >= QFileSystemModel::columnCount() && role == Qt::DisplayRole)
{
QFileInfo info = fileInfo(index);
QString path = info.canonicalFilePath();
QString suffix = info.suffix();
ImageInfoData *infoData = nullptr;
if(_cache->contains(path))
{
infoData = _cache->object(path);
}
else
{
if(_loadFitsKeywords)
{
infoData = new ImageInfoData;
if(isFITS(suffix))
readFITSHeader(path, *infoData);
else if(isXISF(suffix))
readXISFHeader(path, *infoData);
_cache->insert(path, infoData);
}
}
if(infoData)
{
int column = index.column() - QFileSystemModel::columnCount();
if(column < _fitsKeywords.size())
{
const QString &key = _fitsKeywords.at(column);
for(auto &record : infoData->fitsHeader)
if(record.key == key)
return record.value;
}
}
return "";
}
return QFileSystemModel::data(index, role);
}
QVariant DirFileSystemModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if(orientation == Qt::Horizontal && role == Qt::DisplayRole && section >= QFileSystemModel::columnCount())
return _fitsKeywords.at(section - QFileSystemModel::columnCount());
return QFileSystemModel::headerData(section, orientation, role);
}
bool DirFileSystemModel::hasChildren(const QModelIndex &parent) const
{
if(parent.parent() == _dir)return false;
return QFileSystemModel::hasChildren(parent);
}
void DirFileSystemModel::loadFitsKeywords(bool enable)
{
_loadFitsKeywords = enable;
}
DirView::DirView(QWidget *parent) : QTreeView(parent)
{
_dirFileSystemModel = new DirFileSystemModel(this);
_dirFileSystemModel->setRootPath(QDir::drives().first().path());
_dirFileSystemModel->setReadOnly(false);
setDragEnabled(true);
setAcceptDrops(true);
setModel(_dirFileSystemModel);
setSelectionMode(QAbstractItemView::ExtendedSelection);
connect(this, &QTreeView::doubleClicked, [this](const QModelIndex &index){
QFileInfo info = _dirFileSystemModel->fileInfo(index);
if(_dirFileSystemModel->isDir(index))
{
setDir(info.canonicalFilePath());
}
else if(info.isFile())
{
if(_openFilter.contains(info.suffix().toLower()))
emit openFile(info.absoluteFilePath());
else
QDesktopServices::openUrl(QUrl::fromLocalFile(info.absoluteFilePath()));
}
});
header()->setContextMenuPolicy(Qt::CustomContextMenu);
connect(header(), &QHeaderView::customContextMenuRequested, this, &DirView::headerContextMenu);
}
void DirView::setDir(const QString &path)
{
QString oldPath = _dirFileSystemModel->dir();
#ifdef Q_OS_WINDOWS
const int ROOT_LEN = 3;
#else
const int ROOT_LEN = 1;
#endif
if(oldPath.left(ROOT_LEN) != path.left(ROOT_LEN))
_dirFileSystemModel->setRootPath(path.left(ROOT_LEN));
_dirFileSystemModel->setDir(path);
setRootIndex(_dirFileSystemModel->index(path, 0));
clearSelection();
if(oldPath != path)emit dirChanged(path);
}
QString DirView::dir() const
{
return _dirFileSystemModel->dir();
}
void DirView::setOpenFilter(const QSet<QString> &openFilter)
{
_openFilter = openFilter;
}
void DirView::setFITSKeywords(const QStringList &keywords)
{
QString d = dir();
_dirFileSystemModel->setFITSKeywords(keywords);
setDir(d);
}
const QStringList &DirView::FITSKeywords() const
{
return _dirFileSystemModel->FITSKeywords();
}
void DirView::headerContextMenu(const QPoint &pos)
{
QHeaderView *head = header();
QMenu menu;
int count = head->count();
for(int i = 0; i < count; i++)
{
QAction *a = menu.addAction(head->model()->headerData(i, Qt::Horizontal).toString());
a->setCheckable(true);
a->setChecked(!head->isSectionHidden(i));
a->setData(i);
}
QAction *a = menu.exec(mapToGlobal(pos));
if(a)
{
if(a->isChecked())head->showSection(a->data().toInt());
else head->hideSection(a->data().toInt());
}
}
void DirView::loadFitsKeywords(bool enable)
{
_dirFileSystemModel->loadFitsKeywords(enable);
}
-106
View File
@@ -1,106 +0,0 @@
#ifndef FILEMANAGER_H
#define FILEMANAGER_H
#include <QMainWindow>
#include <QCache>
#include <QFileSystemModel>
#include <QTreeView>
#include <QDialog>
#include <QTabBar>
#include <QHBoxLayout>
#include "imageinfodata.h"
namespace Ui {
class FileManager;
class FITSKeyword;
}
class PathTabBar : public QTabBar
{
Q_OBJECT
public:
explicit PathTabBar(const QStringList &tabs);
QHBoxLayout* createLayout();
const QStringList& tabPaths() const;
QString currentTabPath() const;
public slots:
void pathChanged(const QString &path);
signals:
void tabChanged(const QString &path);
private:
QStringList _tabs;
QString tabName(const QString &path);
};
class FITSSelection : public QDialog
{
Q_OBJECT
public:
FITSSelection(const QStringList &keywords, QWidget *parent = nullptr);
~FITSSelection();
QStringList FITSKeywords() const;
private:
Ui::FITSKeyword *ui;
};
class FileManager : public QMainWindow
{
Q_OBJECT
public:
explicit FileManager(const QSet<QString> &openFilter, QWidget *parent = nullptr);
~FileManager();
public slots:
void selectFITSKeywords();
void pathEdited();
signals:
void openFile(const QString &path);
private:
Ui::FileManager *ui;
PathTabBar *_leftTabBar;
PathTabBar *_rightTabBar;
};
class DirFileSystemModel : public QFileSystemModel
{
Q_OBJECT
mutable QCache<QString, ImageInfoData> *_cache = nullptr;
static QCache<QString, ImageInfoData>* getCacheInstance();
QModelIndex _dir;
QStringList _fitsKeywords;
bool _loadFitsKeywords = true;
public:
explicit DirFileSystemModel(QObject *parent = nullptr);
void setDir(const QString &path);
QString dir() const;
void setFITSKeywords(const QStringList &keywords);
const QStringList& FITSKeywords() const;
Qt::ItemFlags flags(const QModelIndex &index) const override;
int columnCount(const QModelIndex &parent) const override;
QVariant data(const QModelIndex &index, int role) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
bool hasChildren(const QModelIndex &parent) const override;
public slots:
void loadFitsKeywords(bool enable);
};
class DirView : public QTreeView
{
Q_OBJECT
DirFileSystemModel *_dirFileSystemModel = nullptr;
QSet<QString> _openFilter;
public:
explicit DirView(QWidget *parent = nullptr);
void setDir(const QString &path);
QString dir() const;
void setOpenFilter(const QSet<QString> &openFilter);
void setFITSKeywords(const QStringList &keywords);
const QStringList& FITSKeywords() const;
public slots:
void headerContextMenu(const QPoint &pos);
void loadFitsKeywords(bool enable);
signals:
void dirChanged(const QString &path);
void openFile(const QString &path);
};
#endif // FILEMANAGER_H
-110
View File
@@ -1,110 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>FileManager</class>
<widget class="QMainWindow" name="FileManager">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1282</width>
<height>858</height>
</rect>
</property>
<property name="windowTitle">
<string>File Manager</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QVBoxLayout" name="leftLayout">
<item>
<widget class="QLineEdit" name="leftPath"/>
</item>
<item>
<widget class="DirView" name="leftTab"/>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="rightLayout">
<item>
<widget class="QLineEdit" name="rightPath"/>
</item>
<item>
<widget class="DirView" name="rightTab"/>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1282</width>
<height>23</height>
</rect>
</property>
<widget class="QMenu" name="menuLeft_Tab">
<property name="title">
<string>Left Tab</string>
</property>
<addaction name="actionLoad_FITS_keywordsLeft"/>
<addaction name="actionSelect_columnsLeft"/>
<addaction name="separator"/>
</widget>
<widget class="QMenu" name="menuRight_Tab">
<property name="title">
<string>Right Tab</string>
</property>
<addaction name="actionLoad_FITS_keywordsRight"/>
<addaction name="actionSelect_columnsRight"/>
<addaction name="separator"/>
</widget>
<addaction name="menuLeft_Tab"/>
<addaction name="menuRight_Tab"/>
</widget>
<action name="actionLoad_FITS_keywordsLeft">
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="text">
<string>Load FITS keywords</string>
</property>
</action>
<action name="actionLoad_FITS_keywordsRight">
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="text">
<string>Load FITS keywords</string>
</property>
</action>
<action name="actionSelect_columnsLeft">
<property name="text">
<string>Select columns</string>
</property>
</action>
<action name="actionSelect_columnsRight">
<property name="text">
<string>Select columns</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>
<class>DirView</class>
<extends>QTreeView</extends>
<header>filemanager.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
-3
View File
@@ -5,7 +5,6 @@
#include <QMenu>
#include <QSettings>
#include <QHeaderView>
#include <QMimeDatabase>
FilesystemWidget::FilesystemWidget(QAbstractItemModel *model, QWidget *parent) : QWidget(parent)
, m_model(model)
@@ -118,7 +117,6 @@ void Filetree::contextMenuEvent(QContextMenuEvent *event)
{
setRootIndex(index);
m_rootDir = m_fileSystemModel->filePath(index);
m_fileSystemModel->setRootPath(m_rootDir);
}
else if(a == resetRoot)
{
@@ -129,7 +127,6 @@ void Filetree::contextMenuEvent(QContextMenuEvent *event)
{
setRootIndex(rootIndex().parent());
m_rootDir = m_fileSystemModel->filePath(rootIndex().parent());
m_fileSystemModel->setRootPath(m_rootDir);
}
else if(a == copy)
{
-1
View File
@@ -3,7 +3,6 @@
#include <QWidget>
#include <QFileSystemModel>
#include <QIdentityProxyModel>
#include <QListView>
#include <QTreeView>
-98
View File
@@ -1,98 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>FITSKeyword</class>
<widget class="QDialog" name="FITSKeyword">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>432</width>
<height>443</height>
</rect>
</property>
<property name="windowTitle">
<string>FITS Columns</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QListWidget" name="keywordList">
<property name="dragEnabled">
<bool>true</bool>
</property>
<property name="dragDropMode">
<enum>QAbstractItemView::InternalMove</enum>
</property>
<property name="defaultDropAction">
<enum>Qt::MoveAction</enum>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="keyword"/>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="addButton">
<property name="text">
<string>Add</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="removeButton">
<property name="text">
<string>Remove</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>FITSKeyword</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>215</x>
<y>420</y>
</hint>
<hint type="destinationlabel">
<x>215</x>
<y>221</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>FITSKeyword</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>215</x>
<y>420</y>
</hint>
<hint type="destinationlabel">
<x>215</x>
<y>221</y>
</hint>
</hints>
</connection>
</connections>
</ui>
-1
View File
@@ -86,7 +86,6 @@ WCSDataT::WCSDataT(int width, int height, const QVector<FITSRecord> &header) :
for(const FITSRecord &record : header)
{
if(record.key.startsWith("PV"))continue;
if(record.xisf)continue;
QByteArray rec;
rec.append(record.key.leftJustified(8, ' '));
+4 -56
View File
@@ -241,59 +241,18 @@ bool loadXISF(const QString &path, ImageInfoData &info, std::shared_ptr<RawImage
{
info.fitsHeader.append(fits);
}
QVector<FITSRecord> xisfWCS;
auto imageproperties = xisfImage.imageProperties();
for(auto prop : imageproperties)
{
info.fitsHeader.append(prop);
if(prop.id == "PCL:AstrometricSolution:ReferenceCelestialCoordinates" && prop.value.type() == LibXISF::Variant::Type::F64Vector)
{
auto val = prop.value.value<LibXISF::F64Vector>();
if(val.size() >= 2)
{
xisfWCS.append({"CRVAL1", val[0], "value from PCL:AstrometricSolution"});
xisfWCS.append({"CRVAL2", val[1], "value from PCL:AstrometricSolution"});
}
}
else if(prop.id == "PCL:AstrometricSolution:ReferenceImageCoordinates" && prop.value.type() == LibXISF::Variant::Type::F64Vector)
{
auto val = prop.value.value<LibXISF::F64Vector>();
if(val.size() >= 2)
{
xisfWCS.append({"CRPIX1", val[0], "value from PCL:AstrometricSolution"});
xisfWCS.append({"CRPIX2", val[1], "value from PCL:AstrometricSolution"});
}
}
else if(prop.id == "PCL:AstrometricSolution:LinearTransformationMatrix" && prop.value.type() == LibXISF::Variant::Type::F64Matrix)
{
auto val = prop.value.value<LibXISF::F64Matrix>();
if(val.cols() >= 2 && val.rows() >= 2)
{
xisfWCS.append({"CD1_1", val(0, 0), "value from PCL:AstrometricSolution"});
xisfWCS.append({"CD1_2", val(0, 1), "value from PCL:AstrometricSolution"});
xisfWCS.append({"CD2_1", val(1, 0), "value from PCL:AstrometricSolution"});
xisfWCS.append({"CD2_2", val(1, 1), "value from PCL:AstrometricSolution"});
}
}
else if(prop.id == "PCL:AstrometricSolution:ProjectionSystem")
{
if(prop.value.toString() == "Gnomonic")
{
xisfWCS.append({"CTYPE1", "RA---TAN", "value from PCL:AstrometricSolution"});
xisfWCS.append({"CTYPE", "DEC--TAN", "value from PCL:AstrometricSolution"});
}
}
}
info.num = xisf.imagesCount();
info.index = index;
info.wcs = std::make_shared<WCSDataT>(xisfImage.width(), xisfImage.height(), info.fitsHeader);
info.info.append({QObject::tr("Width"), QString::number(xisfImage.width())});
info.info.append({QObject::tr("Height"), QString::number(xisfImage.height())});
auto wcs = std::make_shared<WCSDataT>(xisfImage.width(), xisfImage.height(), info.fitsHeader);
if(!wcs->valid() && xisfWCS.size())wcs = std::make_shared<WCSDataT>(xisfImage.width(), xisfImage.height(), xisfWCS);
if(wcs->valid())info.wcs = wcs;
if(!info.wcs->valid())info.wcs.reset();
RawImage::DataType type;
switch(xisfImage.sampleFormat())
@@ -450,19 +409,18 @@ bool loadImage(const QString &path, ImageInfoData &info, std::shared_ptr<RawImag
{
bool ret = false;
QElapsedTimer timer;
QFileInfo fileInfo(path);
timer.start();
if(path.endsWith(".CR2", Qt::CaseInsensitive) || path.endsWith(".CR3", Qt::CaseInsensitive) || path.endsWith(".NEF", Qt::CaseInsensitive) || path.endsWith(".DNG", Qt::CaseInsensitive))
{
ret = loadRAW(path, info, rawImage);
qDebug() << "LoadRAW" << timer.elapsed();
}
else if(isFITS(fileInfo.suffix()))
else if(path.endsWith(".FIT", Qt::CaseInsensitive) || path.endsWith(".FITS", Qt::CaseInsensitive) || path.endsWith(".FZ", Qt::CaseInsensitive) || path.endsWith(".FTS", Qt::CaseInsensitive))
{
ret = loadFITS(path, info, rawImage, planar, index);
qDebug() << "LoadFITS" << timer.elapsed();
}
else if(isXISF(fileInfo.suffix()))
else if(path.endsWith(".XISF", Qt::CaseInsensitive))
{
ret = loadXISF(path, info, rawImage, planar, index);
qDebug() << "LoadXISF" << timer.elapsed();
@@ -486,13 +444,3 @@ bool loadImage(const QString &path, ImageInfoData &info, std::shared_ptr<RawImag
}
return ret;
}
bool isFITS(const QString &suffix)
{
return suffix.compare("fits", Qt::CaseInsensitive) == 0 || suffix.compare("fit", Qt::CaseInsensitive) == 0 || suffix.compare("fts", Qt::CaseInsensitive) == 0 || suffix.compare("fz", Qt::CaseInsensitive) == 0;
}
bool isXISF(const QString &suffix)
{
return suffix.compare("xisf", Qt::CaseInsensitive) == 0;
}
-2
View File
@@ -10,7 +10,5 @@ QString makeUNCPath(const QString &path);
bool readFITSHeader(const QString &path, ImageInfoData &info);
bool readXISFHeader(const QString &path, ImageInfoData &info);
bool loadImage(const QString &path, ImageInfoData &info, std::shared_ptr<RawImage> &rawImage, int index, bool planar = false);
bool isFITS(const QString &suffix);
bool isXISF(const QString &suffix);
#endif // LOADIMAGE_H
+17
View File
@@ -5,9 +5,26 @@
#include <QCommandLineParser>
#include <stdlib.h>
#include "../thumbnailer/genthumbnail.h"
#include <QTreeView>
#include <QFileSystemModel>
#include <QTimer>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QFileSystemModel model;
QTreeView treeView;
QTimer::singleShot(5000, [&model,&treeView](){
treeView.setModel(&model);
model.setRootPath("/home");
});
treeView.resize(800, 600);
treeView.show();
return app.exec();
#ifdef __linux__
setenv("LC_NUMERIC", "C", 1);
#endif
+4 -25
View File
@@ -29,7 +29,6 @@
#include "settingsdialog.h"
#include "histogram.h"
#include "batchprocessing.h"
#include "filemanager.h"
#ifdef __linux__
#include <sys/ioctl.h>
@@ -67,7 +66,6 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
_openFilter.append(tr(";;All files (*)"));
nameFilter.append({"fit", "fits", "fts", "fz", "xisf", "cr2", "cr3", "nef", "dng"});
QImageReader::setAllocationLimit(0);
_openSuffix = {nameFilter.constBegin(), nameFilter.constEnd()};
m_info = new ImageInfo(this);
QDockWidget *infoDock = new QDockWidget(tr("Image info"), this);
@@ -102,14 +100,11 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
connect(m_filesystem, &FilesystemWidget::sortChanged, m_ringList, &ImageRingList::setSort);
connect(m_filesystem, &FilesystemWidget::reverseSort, m_ringList, &ImageRingList::reverseSort);
m_filetree = nullptr;
#if !defined(FLATPAK) || !defined(__aarch64__)//bug with QTreeView and QFileSystemModel on ARM64 under flatpak
m_filetree = new Filetree(this);
connect(m_filetree, &Filetree::fileSelected, this, static_cast<void (MainWindow::*)(const QString &)>(&MainWindow::loadFile));
connect(m_filetree, &Filetree::copyFiles, [this](const QString &path){ copyOrMove(true, path); });
connect(m_filetree, &Filetree::moveFiles, [this](const QString &path){ copyOrMove(false, path); });
connect(m_filetree, &Filetree::indexDirectory, this, static_cast<void (MainWindow::*)(const QString &)>(&MainWindow::indexDir));
#endif
m_databaseView = new DataBaseView(m_database, this);
connect(m_databaseView, &DataBaseView::loadFile, this, static_cast<void (MainWindow::*)(const QString &)>(&MainWindow::loadFile));
@@ -148,14 +143,11 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
databaseViewDock->hide();
addDockWidget(Qt::BottomDockWidgetArea, databaseViewDock);
QDockWidget *filetreeDock = nullptr;
#if !defined(FLATPAK) || !defined(__aarch64__)
filetreeDock = new QDockWidget(tr("File tree"), this);
QDockWidget *filetreeDock = new QDockWidget(tr("File tree"), this);
filetreeDock->setWidget(m_filetree);
filetreeDock->setObjectName("filetreeDock");
databaseViewDock->hide();
addDockWidget(Qt::LeftDockWidgetArea, filetreeDock);
#endif
Histogram *histogram = new Histogram(this);
QDockWidget *histogramDock = new QDockWidget(tr("Histogram"), this);
@@ -184,9 +176,6 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
fileMenu->addAction(tr("Open directory recursively"), this, &MainWindow::loadDir);
QAction *saveAs = fileMenu->addAction(tr("Save as"), QKeySequence::Save, this, &MainWindow::saveAs);
fileMenu->addSeparator();
#if !defined(FLATPAK) || !defined(__aarch64__)
fileMenu->addAction(tr("File manager"), this, &MainWindow::openFileManager);
#endif
fileMenu->addAction(tr("Copy marked files"), Qt::Key_F5, this, &MainWindow::copyMarked);
fileMenu->addAction(tr("Move marked files"), Qt::Key_F6, this, &MainWindow::moveMarked);
fileMenu->addAction(tr("Move marked files to trash"), QKeySequence::Delete, this, &MainWindow::deleteMarked);
@@ -202,7 +191,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
fileMenu->addSeparator();
QAction *liveModeAction = fileMenu->addAction(tr("Live mode"), this, &MainWindow::liveMode);
liveModeAction->setCheckable(true);
QAction *exitAction = fileMenu->addAction(tr("Exit"), QCoreApplication::instance(), &QCoreApplication::quit, Qt::QueuedConnection);
QAction *exitAction = fileMenu->addAction(tr("Exit"), this, &MainWindow::close);
exitAction->setShortcut(QKeySequence::Quit);
menuBar()->addMenu(fileMenu);
@@ -323,7 +312,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
dockMenu->addAction(navigationToolbar->toggleViewAction());
dockMenu->addAction(filesystemDock->toggleViewAction());
dockMenu->addAction(databaseViewDock->toggleViewAction());
if(filetreeDock)dockMenu->addAction(filetreeDock->toggleViewAction());
dockMenu->addAction(filetreeDock->toggleViewAction());
dockMenu->addAction(histogramDock->toggleViewAction());
#ifdef PLATESOLVER
dockMenu->addAction(_plateSolving->toggleViewAction());
@@ -374,8 +363,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
infoDock->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetMovable);
filesystemDock->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetMovable);
databaseViewDock->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetMovable);
if(filetreeDock)filetreeDock->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetMovable);
if(_plateSolving)_plateSolving->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetMovable);
filetreeDock->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetMovable);
m_stretchPanel->setFloatable(false);
}
}
@@ -820,15 +808,6 @@ void MainWindow::checkNewVersion()
});
}
void MainWindow::openFileManager()
{
#if !defined(FLATPAK) || !defined(__aarch64__)
FileManager *filemanager = new FileManager(_openSuffix);
connect(filemanager, &FileManager::openFile, this, static_cast<void (MainWindow::*)(const QString&)>(&MainWindow::loadFile));
filemanager->show();
#endif
}
void MainWindow::updateWindowTitle()
{
ImagePtr ptr = m_ringList->currentImage();
+1 -3
View File
@@ -23,14 +23,13 @@ class MainWindow : public QMainWindow
FilesystemWidget *m_filesystem;
Filetree *m_filetree;
DataBaseView *m_databaseView;
PlateSolving *_plateSolving = nullptr;
PlateSolving *_plateSolving;
static int socketPair[2];
QSocketNotifier *socketNotifier;
QString _lastDir;
bool _maximized;
QString _openFilter;
QString _saveFilter;
QSet<QString> _openSuffix;
public:
MainWindow(QWidget *parent = 0);
~MainWindow() override;
@@ -68,7 +67,6 @@ public slots:
void showSettingsDialog();
void exportCSV();
void checkNewVersion();
void openFileManager();
};
#endif // MAINWINDOW_H
+1 -1
View File
@@ -1,7 +1,7 @@
#ifndef PLATESOLVING_H
#define PLATESOLVING_H
#include <QElapsedTimer>
#include "qelapsedtimer.h"
#include <QDockWidget>
class Solver;
+2 -2
View File
@@ -403,9 +403,9 @@ uint32_t RawImage::norm() const
}
}
uint64_t RawImage::widthBytes() const
uint32_t RawImage::widthBytes() const
{
return (uint64_t)m_ch * m_width * typeSize(m_type);
return m_ch * m_width * typeSize(m_type);
}
uint32_t RawImage::widthSamples() const
+1 -1
View File
@@ -97,7 +97,7 @@ public:
uint64_t size() const;
DataType type() const;
uint32_t norm() const;
uint64_t widthBytes() const;
uint32_t widthBytes() const;
uint32_t widthSamples() const;
void* data();
const void* data() const;
+10 -35
View File
@@ -455,11 +455,11 @@ void File::loadFitsKeywords()
{
_fitsKeywordsLoaded = true;
ImageInfoData info;
if(isXISF(suffix()))
if(suffix().toLower() == "xisf")
{
readXISFHeader(_path, info);
}
else if(isFITS(suffix()))
else if(suffix().toLower() == "fits" || suffix().toLower() == "fit" || suffix().toLower() == "fz")
{
readFITSHeader(_path, info);
}
@@ -608,7 +608,7 @@ bool File::modifyFITSRecords(const FITSRecordModify *modify)
_fitsKeywordsLoaded = false;
_fitsKeywords.clear();
if(isFITS(suffix()))
if(QRegularExpression("(fits?|fz|fts)", QRegularExpression::CaseInsensitiveOption).match(suffix()).hasMatch())
{
fitsfile *file;
int status = 0;
@@ -625,21 +625,15 @@ bool File::modifyFITSRecords(const FITSRecordModify *modify)
int naxis;
long naxes[3] = {0};
int type = -1;
std::vector<int> imageIdxs;
for(int i=1; i <= num; i++)
{
fits_movabs_hdu(file, i, IMAGE_HDU, &status);
fits_get_hdu_type(file, &type, &status);
if(type == IMAGE_HDU)
{
fits_get_img_param(file, 3, &imgtype, &naxis, naxes, &status);
if(naxis >= 2 && naxis <= 3)imageIdxs.push_back(i);
if(type == IMAGE_HDU && naxis >= 2 && naxis <= 3 && status == 0)
break;
if(i == num)return false;
}
}
if(modify->_imageIdx >= imageIdxs.size())return false;
fits_movabs_hdu(file, imageIdxs[modify->_imageIdx], &type, &status);
fits_get_img_param(file, 3, &imgtype, &naxis, naxes, &status);
for(auto &remove : modify->_remove)
{
@@ -737,7 +731,7 @@ bool File::modifyFITSRecords(const FITSRecordModify *modify)
return status == 0;
}
else if(isXISF(suffix()))
else if(suffix().toLower() == "xisf")
{
try
{
@@ -748,16 +742,13 @@ bool File::modifyFITSRecords(const FITSRecordModify *modify)
qDebug() << "modify" << in << out;
for(auto &remove : modify->_remove)
modifyXISF.removeFITSKeyword(modify->_imageIdx, remove.toStdString());
modifyXISF.removeFITSKeyword(0, remove.toStdString());
for(auto &record : modify->_update)
modifyXISF.updateFITSKeyword(modify->_imageIdx, {record.key.toStdString(), record.value.toString().toStdString(), record.comment.toStdString()}, true);
modifyXISF.updateFITSKeyword(0, {record.key.toStdString(), record.value.toString().toStdString(), record.comment.toStdString()}, true);
for(auto &record : modify->_add)
modifyXISF.addFITSKeyword(modify->_imageIdx, {record.key.toStdString(), record.value.toString().toStdString(), record.comment.toStdString()});
for(auto &property : modify->_property)
modifyXISF.updateProperty(modify->_imageIdx, property);
modifyXISF.addFITSKeyword(0, {record.key.toStdString(), record.value.toString().toStdString(), record.comment.toStdString()});
modifyXISF.save(out.toLocal8Bit().toStdString());
modifyXISF.close();
@@ -766,7 +757,6 @@ bool File::modifyFITSRecords(const FITSRecordModify *modify)
}
catch(std::filesystem::filesystem_error &err)
{
if(_engine)_engine->newMessage("Failed to modify file " + _path + " " + err.what(), true);
return false;
}
catch(LibXISF::Error &err)
@@ -936,21 +926,6 @@ void FITSRecordModify::addKeyword(const QString &key, const QVariant &value, con
_update.append({key.toLatin1(), value, comment.toLatin1()});
}
void FITSRecordModify::updateProperty(const QString &id, const LibXISF::Variant &value)
{
_property.append(LibXISF::Property(id.toStdString(), value));
}
uint32_t FITSRecordModify::imageIndex() const
{
return _imageIdx;
}
void FITSRecordModify::setImageIndex(uint32_t idx)
{
_imageIdx = idx;
}
bool TextFile::open(const QString &path, const QString &mode)
{
_fr.setFileName(path);
-7
View File
@@ -9,7 +9,6 @@
#include <QSemaphore>
#include "database.h"
#include "imageinfodata.h"
#include "libxisf.h"
class BatchProcessing;
class Solver;
@@ -141,8 +140,6 @@ class FITSRecordModify : public QObject
QStringList _remove;
QVector<FITSRecord> _update;
QVector<FITSRecord> _add;
QVector<LibXISF::Property> _property;
uint32_t _imageIdx = 0;
friend class File;
public:
@@ -150,10 +147,6 @@ public:
Q_INVOKABLE void removeKeyword(const QString &key);
Q_INVOKABLE void updateKeyword(const QString &key, const QVariant &value, const QString &comment = QString());
Q_INVOKABLE void addKeyword(const QString &key, const QVariant &value, const QString &comment = QString());
Q_PROPERTY(uint32_t imageIndex READ imageIndex WRITE setImageIndex);
void updateProperty(const QString &id, const LibXISF::Variant &value);
uint32_t imageIndex() const;
void setImageIndex(uint32_t idx);
};
class TextFile : public QObject
-13
View File
@@ -186,19 +186,6 @@ bool Solver::updateHeader(QString &error)
modify.updateKeyword("CTYPE2", "DEC--TAN", QByteArray("first parameter DEC, projection TANgential"));
modify.updateKeyword("RADESYS", "ICRS", QByteArray("International Celestial Reference System"));
modify.updateKeyword("EQUINOX", 2000, QByteArray("Equinox of coordinates"));
LibXISF::F64Matrix matrix(2, 2);
matrix(0, 0) = std::cos(rotationRad) * cdeltx;
matrix(0, 1) =-std::sin(rotationRad) * cdelty;
matrix(1, 0) = std::sin(rotationRad) * cdeltx;
matrix(1, 1) = std::cos(rotationRad) * cdelty;
modify.updateProperty("PCL:AstrometricSolution:ReferenceCelestialCoordinates", LibXISF::F64Vector({solution.ra, solution.dec}));
modify.updateProperty("PCL:AstrometricSolution:ReferenceImageCoordinates", LibXISF::F64Vector({_stats.width / 2.0, _stats.height / 2.0}));
modify.updateProperty("PCL:AstrometricSolution:LinearTransformationMatrix", LibXISF::F64Matrix(matrix));
modify.updateProperty("PCL:AstrometricSolution:ProjectionSystem", LibXISF::String("Gnomonic"));
modify.updateProperty("PCL:AstrometricSolution:ReferenceNativeCoordinates", LibXISF::F64Vector({0, 90}));
bool ret = file.modifyFITSRecords(&modify);
if(!ret)error = tr("Failed to update file header");
else emit headerUpdated(_path);