Compare commits

...

10 Commits

8 changed files with 125 additions and 13 deletions
+2 -2
View File
@@ -17,7 +17,7 @@ if(SANITIZE_ADDRESS_LEAK)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fsanitize=address -fsanitize=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(FITS_LIB cfitsio 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}")
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)
target_link_libraries(tenmon PRIVATE Qt6::DBus "-framework CoreFoundation")
elseif(UNIX)
+13 -1
View File
@@ -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 minDec_idx ON fits_files(minDec)");
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";
return false;
@@ -307,6 +314,11 @@ QVector<SkyObject> Database::getObjects(double minRa, double maxRa, double minDe
return objects;
}
const QSqlDatabase &Database::db() const
{
return database;
}
bool Database::indexDir2(const QDir &dir, QProgressDialog *progress, QStringList &scannedDirs)
{
if(scannedDirs.contains(dir.canonicalPath()))return true;
+1
View File
@@ -42,6 +42,7 @@ public:
void reindex(QProgressDialog *progress);
QStringList getFitsKeywords();
QVector<SkyObject> getObjects(double minRa, double maxRa, double minDec, double maxDec);
const QSqlDatabase& db() const;
protected:
bool indexDir2(const QDir &dir, QProgressDialog *progress, QStringList &scannedDirs);
bool indexFile(const QFileInfo &file);
+87 -9
View File
@@ -9,6 +9,9 @@
#include <QMenu>
#include <QContextMenuEvent>
#include <QRegularExpression>
#include <QGuiApplication>
#include <QClipboard>
#include <QMimeData>
#include <iostream>
#include "batchprocessing.h"
@@ -157,32 +160,67 @@ void FITSFileModel::filesUnmarked(const QModelIndexList &indexes)
}
}
void FITSFileModel::load()
{
if(!m_loaded)
{
m_loaded = true;
prepareQuery();
}
}
void FITSFileModel::prepareQuery()
{
if(!m_loaded)return;
QString cols;
QString join;
QStringList where;
QString sql = m_columns.size() ? "SELECT f.file," : "SELECT f.file";
QVariantList bindValues;
QVariantList bindValuesJoin;
for(int i=0; i<m_value.size(); i++)
{
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")
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")
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")
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")
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
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;
for(auto &column : m_columns)
{
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++;
}
cols.chop(1);
@@ -191,7 +229,18 @@ void FITSFileModel::prepareQuery()
sql += join;
if(!where.isEmpty())sql += " WHERE " + where.join("AND");
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"));
i = 1;
for(auto &column : m_columns)
@@ -217,6 +266,7 @@ void DatabaseTableView::contextMenuEvent(QContextMenuEvent *event)
QAction *unmark = menu.addAction(tr("Unmark"));
QAction *open = menu.addAction(tr("Open"));
QAction *openDirAction = menu.addAction(tr("Open file location"));
QAction *copyPath = menu.addAction(tr("Copy files"));
QAction *a = menu.exec(event->globalPos());
if(a == nullptr)
@@ -232,6 +282,22 @@ void DatabaseTableView::contextMenuEvent(QContextMenuEvent *event)
emit openFile(indexes);
else if(a == openDirAction)
emit openDir(indexes);
else if(a == copyPath)
{
QStringList paths;
QList<QUrl> urls;
for(auto &index : indexes)
{
QString path = index.siblingAtColumn(0).data().toString();
paths.append(path);
urls.append(QUrl::fromLocalFile(path));
}
QMimeData *data = new QMimeData;
data->setUrls(urls);
data->setText(paths.join('\n'));
QClipboard *clipboard = QGuiApplication::clipboard();
clipboard->setMimeData(data);
}
}
DataBaseView::DataBaseView(Database *database, QWidget *parent) : QWidget(parent)
@@ -300,12 +366,13 @@ DataBaseView::DataBaseView(Database *database, QWidget *parent) : QWidget(parent
};
QStringList fitsKeywords = m_database->getFitsKeywords();
QStringList filterKey = settings.value("databaseview/filterKey", QStringList{"file", "file", "file"}).toStringList();
for(int i=0; i<3; i++)
{
m_filterKeyword[i] = new QComboBox(this);
m_filterKeyword[i]->setMaximumWidth(300);
addFilterItems(m_filterKeyword[i], fitsKeywords);
m_filterKeyword[i]->setCurrentText(filterKey[i]);
m_search[i] = new QLineEdit(this);
m_search[i]->setPlaceholderText(tr("Text to search, you can % as wildcard"));
@@ -339,8 +406,13 @@ DataBaseView::DataBaseView(Database *database, QWidget *parent) : QWidget(parent
DataBaseView::~DataBaseView()
{
QStringList filterKey;
for(int i = 0; i < 3; i++)
filterKey.append(m_filterKeyword[i]->currentText());
QSettings settings;
settings.setValue("databaseview/header", m_tableView->horizontalHeader()->saveState());
settings.setValue("databaseview/filterKey", filterKey);
}
void DataBaseView::selectColumns()
@@ -392,6 +464,7 @@ bool DataBaseView::exportCSV(const QString &path)
if(!csv.open(QIODevice::WriteOnly | QIODevice::Text))
return false;
m_model->load();
QSqlQuery sql(m_model->query().lastQuery());
int colCount = m_model->columnCount();
QStringList header;
@@ -420,3 +493,8 @@ bool DataBaseView::exportCSV(const QString &path)
}
return true;
}
void DataBaseView::visible(bool visible)
{
if(visible)m_model->load();
}
+3
View File
@@ -30,6 +30,7 @@ class FITSFileModel : public QSqlQueryModel
QStringList m_limit;
QSet<QString> m_markedFiles;
Database *m_database;
bool m_loaded = false;
public:
explicit FITSFileModel(Database *database, QObject *parent = nullptr);
void sort(int column, Qt::SortOrder order) override;
@@ -38,6 +39,7 @@ public:
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
void filesMarked(const QModelIndexList &indexes);
void filesUnmarked(const QModelIndexList &indexes);
void load();
protected:
void prepareQuery();
};
@@ -74,6 +76,7 @@ public slots:
void itemActivated(const QModelIndex &index);
void applyFilter();
bool exportCSV(const QString &path);
void visible(bool visible);
signals:
void loadFile(QString file);
};
+1
View File
@@ -30,6 +30,7 @@ FITSRecord::FITSRecord(const LibXISF::FITSKeyword &record)
string.chop(1);
string.remove(0, 1);
}
string = string.trimmed();
bool isint;
bool isdouble;
double vald = string.toDouble(&isdouble);
+11
View File
@@ -6,6 +6,9 @@
#include <QSettings>
#include <stdlib.h>
#include "../thumbnailer/genthumbnail.h"
#ifdef Q_OS_WIN64
#include <windows.h>
#endif
int main(int argc, char *argv[])
{
@@ -19,6 +22,14 @@ int main(int argc, char *argv[])
bool useGLES = true;
#endif
#ifdef Q_OS_WIN64
if(AttachConsole(ATTACH_PARENT_PROCESS))
{
freopen("CONOUT$", "w", stdout);
freopen("CONOUT$", "w", stderr);
}
#endif
QCommandLineParser cmd;
cmd.addOption({"gl", "Use desktop OpenGL. This is default on x86 and MacOS platform."});
cmd.addOption({"gles", "Use OpenGL ES. This is default on ARM platform."});
+7 -1
View File
@@ -153,6 +153,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
databaseViewDock->setWidget(m_databaseView);
databaseViewDock->setObjectName("databaseViewDock");
databaseViewDock->hide();
connect(databaseViewDock, &QDockWidget::visibilityChanged, m_databaseView, &DataBaseView::visible);
addDockWidget(Qt::BottomDockWidgetArea, databaseViewDock);
QDockWidget *filetreeDock = nullptr;
@@ -196,7 +197,12 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
#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);
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->addAction(tr("Index directory"), this, static_cast<void (MainWindow::*)()>(&MainWindow::indexDir));
fileMenu->addAction(tr("Reindex files"), this, &MainWindow::reindex);