Compare commits
8 Commits
20260217
...
b7f1a0abc9
| Author | SHA1 | Date | |
|---|---|---|---|
| b7f1a0abc9 | |||
| 33c976d3c9 | |||
| a17001cdf9 | |||
| 305c1d1f55 | |||
| 95808b094d | |||
| 2b56af27fe | |||
| 8edf746827 | |||
| 729a330e6c |
+2
-2
@@ -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 Qml Charts REQUIRED)
|
find_package(Qt6 COMPONENTS Widgets Sql OpenGLWidgets Qml Charts Svg REQUIRED)
|
||||||
find_library(EXIF_LIB exif REQUIRED)
|
find_library(EXIF_LIB exif REQUIRED)
|
||||||
find_library(FITS_LIB cfitsio REQUIRED)
|
find_library(FITS_LIB cfitsio REQUIRED)
|
||||||
find_library(RAW_LIB NAMES raw_r REQUIRED)
|
find_library(RAW_LIB NAMES raw_r REQUIRED)
|
||||||
@@ -105,7 +105,7 @@ if(STELLARSOLVER_INCLUDE AND STELLARSOLVER_LIB)
|
|||||||
message(STATUS "Found stellarsolver ${STELLARSOLVER_INCLUDE} ${STELLARSOLVER_LIB}")
|
message(STATUS "Found stellarsolver ${STELLARSOLVER_INCLUDE} ${STELLARSOLVER_LIB}")
|
||||||
endif(STELLARSOLVER_INCLUDE AND STELLARSOLVER_LIB)
|
endif(STELLARSOLVER_INCLUDE AND STELLARSOLVER_LIB)
|
||||||
|
|
||||||
target_link_libraries(tenmon PRIVATE Qt6::Widgets Qt6::Sql Qt6::OpenGLWidgets Qt6::Qml Qt6::Charts ${EXIF_LIB} ${FITS_LIB} ${RAW_LIB} ${WCS_LIB} ${LCMS2_LIB} XISF)
|
target_link_libraries(tenmon PRIVATE Qt6::Widgets Qt6::Sql Qt6::OpenGLWidgets Qt6::Qml Qt6::Charts Qt6::Svg ${EXIF_LIB} ${FITS_LIB} ${RAW_LIB} ${WCS_LIB} ${LCMS2_LIB} XISF)
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
target_link_libraries(tenmon PRIVATE Qt6::DBus "-framework CoreFoundation")
|
target_link_libraries(tenmon PRIVATE Qt6::DBus "-framework CoreFoundation")
|
||||||
elseif(UNIX)
|
elseif(UNIX)
|
||||||
|
|||||||
+13
-1
@@ -61,8 +61,15 @@ bool Database::init(const QLatin1String &connectionName)
|
|||||||
query.exec("CREATE INDEX IF NOT EXISTS maxRa_idx ON fits_files(maxRa)");
|
query.exec("CREATE INDEX IF NOT EXISTS maxRa_idx ON fits_files(maxRa)");
|
||||||
query.exec("CREATE INDEX IF NOT EXISTS minDec_idx ON fits_files(minDec)");
|
query.exec("CREATE INDEX IF NOT EXISTS minDec_idx ON fits_files(minDec)");
|
||||||
query.exec("CREATE INDEX IF NOT EXISTS maxDec_idx ON fits_files(maxDec)");
|
query.exec("CREATE INDEX IF NOT EXISTS maxDec_idx ON fits_files(maxDec)");
|
||||||
|
version = 1;
|
||||||
}
|
}
|
||||||
else if(version > 1)
|
if(version == 1)
|
||||||
|
{
|
||||||
|
query.exec("CREATE INDEX IF NOT EXISTS id_file_key ON fits_headers(id_file, key)");
|
||||||
|
query.exec("PRAGMA user_version = 2");
|
||||||
|
version = 2;
|
||||||
|
}
|
||||||
|
if(version > 2)
|
||||||
{
|
{
|
||||||
qDebug() << "Database version is too new";
|
qDebug() << "Database version is too new";
|
||||||
return false;
|
return false;
|
||||||
@@ -307,6 +314,11 @@ QVector<SkyObject> Database::getObjects(double minRa, double maxRa, double minDe
|
|||||||
return objects;
|
return objects;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const QSqlDatabase &Database::db() const
|
||||||
|
{
|
||||||
|
return database;
|
||||||
|
}
|
||||||
|
|
||||||
bool Database::indexDir2(const QDir &dir, QProgressDialog *progress, QStringList &scannedDirs)
|
bool Database::indexDir2(const QDir &dir, QProgressDialog *progress, QStringList &scannedDirs)
|
||||||
{
|
{
|
||||||
if(scannedDirs.contains(dir.canonicalPath()))return true;
|
if(scannedDirs.contains(dir.canonicalPath()))return true;
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ public:
|
|||||||
void reindex(QProgressDialog *progress);
|
void reindex(QProgressDialog *progress);
|
||||||
QStringList getFitsKeywords();
|
QStringList getFitsKeywords();
|
||||||
QVector<SkyObject> getObjects(double minRa, double maxRa, double minDec, double maxDec);
|
QVector<SkyObject> getObjects(double minRa, double maxRa, double minDec, double maxDec);
|
||||||
|
const QSqlDatabase& db() const;
|
||||||
protected:
|
protected:
|
||||||
bool indexDir2(const QDir &dir, QProgressDialog *progress, QStringList &scannedDirs);
|
bool indexDir2(const QDir &dir, QProgressDialog *progress, QStringList &scannedDirs);
|
||||||
bool indexFile(const QFileInfo &file);
|
bool indexFile(const QFileInfo &file);
|
||||||
|
|||||||
+67
-9
@@ -157,32 +157,67 @@ void FITSFileModel::filesUnmarked(const QModelIndexList &indexes)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FITSFileModel::load()
|
||||||
|
{
|
||||||
|
if(!m_loaded)
|
||||||
|
{
|
||||||
|
m_loaded = true;
|
||||||
|
prepareQuery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void FITSFileModel::prepareQuery()
|
void FITSFileModel::prepareQuery()
|
||||||
{
|
{
|
||||||
|
if(!m_loaded)return;
|
||||||
|
|
||||||
QString cols;
|
QString cols;
|
||||||
QString join;
|
QString join;
|
||||||
QStringList where;
|
QStringList where;
|
||||||
QString sql = m_columns.size() ? "SELECT f.file," : "SELECT f.file";
|
QString sql = m_columns.size() ? "SELECT f.file," : "SELECT f.file";
|
||||||
|
QVariantList bindValues;
|
||||||
|
QVariantList bindValuesJoin;
|
||||||
for(int i=0; i<m_value.size(); i++)
|
for(int i=0; i<m_value.size(); i++)
|
||||||
{
|
{
|
||||||
if(m_key[i] == "file")
|
if(m_key[i] == "file")
|
||||||
where.append(QString(" f.file LIKE '%1' ").arg(m_value[i]));
|
{
|
||||||
|
where.append(" f.file LIKE ? ");
|
||||||
|
bindValues.append(m_value[i]);
|
||||||
|
}
|
||||||
else if(m_key[i] == "RA pos")
|
else if(m_key[i] == "RA pos")
|
||||||
where.append(QString(" %1 BETWEEN f.minRa AND f.maxRa ").arg(RA(m_value[i])));
|
{
|
||||||
|
where.append(" ? BETWEEN f.minRa AND f.maxRa ");
|
||||||
|
bindValues.append(RA(m_value[i]));
|
||||||
|
}
|
||||||
else if(m_key[i] == "DEC pos")
|
else if(m_key[i] == "DEC pos")
|
||||||
where.append(QString(" %1 BETWEEN f.minDec AND f.maxDec ").arg(DEC(m_value[i])));
|
{
|
||||||
|
where.append(" ? BETWEEN f.minDec AND f.maxDec ");
|
||||||
|
bindValues.append(DEC(m_value[i]));
|
||||||
|
}
|
||||||
else if(m_key[i] == "RA range")
|
else if(m_key[i] == "RA range")
|
||||||
where.append(QString(" crVal1 BETWEEN %1 AND %2 ").arg(RA(m_value[i])).arg(RA(m_limit[i])));
|
{
|
||||||
|
where.append(" crVal1 BETWEEN ? AND ? ");
|
||||||
|
bindValues.append(RA(m_value[i]));
|
||||||
|
bindValues.append(RA(m_limit[i]));
|
||||||
|
}
|
||||||
else if(m_key[i] == "DEC range")
|
else if(m_key[i] == "DEC range")
|
||||||
where.append(QString(" crVal2 BETWEEN %1 AND %2 ").arg(DEC(m_value[i])).arg(DEC(m_limit[i])));
|
{
|
||||||
|
where.append(" crVal2 BETWEEN ? AND ? ");
|
||||||
|
bindValues.append(DEC(m_value[i]));
|
||||||
|
bindValues.append(DEC(m_limit[i]));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
join += QString(" JOIN fits_headers AS s%1 ON f.id=s%1.id_file AND s%1.key='%2' AND s%1.value LIKE '%3'").arg(i).arg(m_key[i]).arg(m_value[i]);
|
{
|
||||||
|
join += QString(" JOIN fits_headers AS s%1 ON f.id=s%1.id_file AND s%1.key=? AND s%1.value LIKE ? ").arg(i);
|
||||||
|
bindValuesJoin.append(m_key[i]);
|
||||||
|
bindValuesJoin.append(m_value[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
int i=0;
|
int i=0;
|
||||||
for(auto &column : m_columns)
|
for(auto &column : m_columns)
|
||||||
{
|
{
|
||||||
cols += QString("GROUP_CONCAT(h%1.value) AS h%1_value,").arg(i);
|
cols += QString("GROUP_CONCAT(h%1.value) AS h%1_value,").arg(i);
|
||||||
join += QString(" LEFT JOIN fits_headers AS h%1 ON f.id=h%1.id_file AND h%1.key='%2'").arg(i).arg(column);
|
join += QString(" LEFT JOIN fits_headers AS h%1 ON f.id=h%1.id_file AND h%1.key=?").arg(i);
|
||||||
|
bindValuesJoin.append(column);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
cols.chop(1);
|
cols.chop(1);
|
||||||
@@ -191,7 +226,18 @@ void FITSFileModel::prepareQuery()
|
|||||||
sql += join;
|
sql += join;
|
||||||
if(!where.isEmpty())sql += " WHERE " + where.join("AND");
|
if(!where.isEmpty())sql += " WHERE " + where.join("AND");
|
||||||
sql += " GROUP BY f.id" + m_sort;
|
sql += " GROUP BY f.id" + m_sort;
|
||||||
setQuery(sql);
|
|
||||||
|
QSqlQuery query(m_database->db());
|
||||||
|
query.prepare(sql);
|
||||||
|
for(auto &val : bindValuesJoin)
|
||||||
|
query.addBindValue(val);
|
||||||
|
for(auto &val : bindValues)
|
||||||
|
query.addBindValue(val);
|
||||||
|
|
||||||
|
if(!query.exec())
|
||||||
|
qWarning() << "Failed to exectute query" << query.lastQuery() << bindValuesJoin << bindValues;
|
||||||
|
setQuery(std::move(query));
|
||||||
|
|
||||||
setHeaderData(0, Qt::Horizontal, tr("File name"));
|
setHeaderData(0, Qt::Horizontal, tr("File name"));
|
||||||
i = 1;
|
i = 1;
|
||||||
for(auto &column : m_columns)
|
for(auto &column : m_columns)
|
||||||
@@ -300,12 +346,13 @@ DataBaseView::DataBaseView(Database *database, QWidget *parent) : QWidget(parent
|
|||||||
};
|
};
|
||||||
|
|
||||||
QStringList fitsKeywords = m_database->getFitsKeywords();
|
QStringList fitsKeywords = m_database->getFitsKeywords();
|
||||||
|
QStringList filterKey = settings.value("databaseview/filterKey", QStringList{"file", "file", "file"}).toStringList();
|
||||||
for(int i=0; i<3; i++)
|
for(int i=0; i<3; i++)
|
||||||
{
|
{
|
||||||
m_filterKeyword[i] = new QComboBox(this);
|
m_filterKeyword[i] = new QComboBox(this);
|
||||||
m_filterKeyword[i]->setMaximumWidth(300);
|
m_filterKeyword[i]->setMaximumWidth(300);
|
||||||
addFilterItems(m_filterKeyword[i], fitsKeywords);
|
addFilterItems(m_filterKeyword[i], fitsKeywords);
|
||||||
|
m_filterKeyword[i]->setCurrentText(filterKey[i]);
|
||||||
|
|
||||||
m_search[i] = new QLineEdit(this);
|
m_search[i] = new QLineEdit(this);
|
||||||
m_search[i]->setPlaceholderText(tr("Text to search, you can % as wildcard"));
|
m_search[i]->setPlaceholderText(tr("Text to search, you can % as wildcard"));
|
||||||
@@ -339,8 +386,13 @@ DataBaseView::DataBaseView(Database *database, QWidget *parent) : QWidget(parent
|
|||||||
|
|
||||||
DataBaseView::~DataBaseView()
|
DataBaseView::~DataBaseView()
|
||||||
{
|
{
|
||||||
|
QStringList filterKey;
|
||||||
|
for(int i = 0; i < 3; i++)
|
||||||
|
filterKey.append(m_filterKeyword[i]->currentText());
|
||||||
|
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
settings.setValue("databaseview/header", m_tableView->horizontalHeader()->saveState());
|
settings.setValue("databaseview/header", m_tableView->horizontalHeader()->saveState());
|
||||||
|
settings.setValue("databaseview/filterKey", filterKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DataBaseView::selectColumns()
|
void DataBaseView::selectColumns()
|
||||||
@@ -392,6 +444,7 @@ bool DataBaseView::exportCSV(const QString &path)
|
|||||||
if(!csv.open(QIODevice::WriteOnly | QIODevice::Text))
|
if(!csv.open(QIODevice::WriteOnly | QIODevice::Text))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
m_model->load();
|
||||||
QSqlQuery sql(m_model->query().lastQuery());
|
QSqlQuery sql(m_model->query().lastQuery());
|
||||||
int colCount = m_model->columnCount();
|
int colCount = m_model->columnCount();
|
||||||
QStringList header;
|
QStringList header;
|
||||||
@@ -420,3 +473,8 @@ bool DataBaseView::exportCSV(const QString &path)
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DataBaseView::visible(bool visible)
|
||||||
|
{
|
||||||
|
if(visible)m_model->load();
|
||||||
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ class FITSFileModel : public QSqlQueryModel
|
|||||||
QStringList m_limit;
|
QStringList m_limit;
|
||||||
QSet<QString> m_markedFiles;
|
QSet<QString> m_markedFiles;
|
||||||
Database *m_database;
|
Database *m_database;
|
||||||
|
bool m_loaded = false;
|
||||||
public:
|
public:
|
||||||
explicit FITSFileModel(Database *database, QObject *parent = nullptr);
|
explicit FITSFileModel(Database *database, QObject *parent = nullptr);
|
||||||
void sort(int column, Qt::SortOrder order) override;
|
void sort(int column, Qt::SortOrder order) override;
|
||||||
@@ -38,6 +39,7 @@ public:
|
|||||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||||
void filesMarked(const QModelIndexList &indexes);
|
void filesMarked(const QModelIndexList &indexes);
|
||||||
void filesUnmarked(const QModelIndexList &indexes);
|
void filesUnmarked(const QModelIndexList &indexes);
|
||||||
|
void load();
|
||||||
protected:
|
protected:
|
||||||
void prepareQuery();
|
void prepareQuery();
|
||||||
};
|
};
|
||||||
@@ -74,6 +76,7 @@ public slots:
|
|||||||
void itemActivated(const QModelIndex &index);
|
void itemActivated(const QModelIndex &index);
|
||||||
void applyFilter();
|
void applyFilter();
|
||||||
bool exportCSV(const QString &path);
|
bool exportCSV(const QString &path);
|
||||||
|
void visible(bool visible);
|
||||||
signals:
|
signals:
|
||||||
void loadFile(QString file);
|
void loadFile(QString file);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ FITSRecord::FITSRecord(const LibXISF::FITSKeyword &record)
|
|||||||
string.chop(1);
|
string.chop(1);
|
||||||
string.remove(0, 1);
|
string.remove(0, 1);
|
||||||
}
|
}
|
||||||
|
string = string.trimmed();
|
||||||
bool isint;
|
bool isint;
|
||||||
bool isdouble;
|
bool isdouble;
|
||||||
double vald = string.toDouble(&isdouble);
|
double vald = string.toDouble(&isdouble);
|
||||||
|
|||||||
+6
-1
@@ -196,7 +196,12 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
|
|||||||
#endif
|
#endif
|
||||||
fileMenu->addAction(tr("Copy marked files"), Qt::Key_F5, this, &MainWindow::copyMarked);
|
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"), Qt::Key_F6, this, &MainWindow::moveMarked);
|
||||||
fileMenu->addAction(tr("Move marked files to trash"), QKeySequence::Delete, this, &MainWindow::deleteMarked);
|
QAction *deleteAction = fileMenu->addAction(tr("Move marked files to trash"), QKeySequence::Delete, this, &MainWindow::deleteMarked);
|
||||||
|
#ifdef Q_OS_MACOS
|
||||||
|
deleteAction->setShortcuts(QList<QKeySequence>({Qt::Key_Backspace, QKeySequence::Delete}));
|
||||||
|
#else
|
||||||
|
deleteAction->setShortcuts(QKeySequence::Delete);
|
||||||
|
#endif
|
||||||
fileMenu->addSeparator();
|
fileMenu->addSeparator();
|
||||||
fileMenu->addAction(tr("Index directory"), this, static_cast<void (MainWindow::*)()>(&MainWindow::indexDir));
|
fileMenu->addAction(tr("Index directory"), this, static_cast<void (MainWindow::*)()>(&MainWindow::indexDir));
|
||||||
fileMenu->addAction(tr("Reindex files"), this, &MainWindow::reindex);
|
fileMenu->addAction(tr("Reindex files"), this, &MainWindow::reindex);
|
||||||
|
|||||||
Reference in New Issue
Block a user