From 04e2cfa29097e65706730d03d898e52f25731cfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Du=C5=A1an=20Poizl?= Date: Sat, 9 Apr 2022 12:40:40 +0200 Subject: [PATCH] Add database indexing of FITS files --- CMakeLists.txt | 1 + database.cpp | 2 +- databaseview.cpp | 112 +++++++++++++++++++++++++++++++++++++++++++++++ databaseview.h | 37 ++++++++++++++++ mainwindow.cpp | 24 ++++++++-- mainwindow.h | 3 ++ 6 files changed, 174 insertions(+), 5 deletions(-) create mode 100644 databaseview.cpp create mode 100644 databaseview.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 16aff40..5c7d2c6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,6 +18,7 @@ find_library(RAW_LIB NAMES raw_r raw REQUIRED) set(TENMON_SRC database.cpp + databaseview.cpp filesystemwidget.cpp imageinfo.cpp imageringlist.cpp diff --git a/database.cpp b/database.cpp index ce676e8..268f000 100644 --- a/database.cpp +++ b/database.cpp @@ -48,7 +48,7 @@ bool Database::init() m_checkFile = QSqlQuery(m_database); m_checkFile.prepare("SELECT id,mtime FROM fits_files WHERE file=?"); m_headerKeywords = QSqlQuery(m_database); - m_headerKeywords.prepare("SELECT DISTINCT key FROM fits_headers"); + m_headerKeywords.prepare("SELECT DISTINCT key FROM fits_headers ORDER BY key"); m_deleteFile = QSqlQuery(m_database); m_deleteFile.prepare("DELETE FROM fits_files WHERE id=?"); return true; diff --git a/databaseview.cpp b/databaseview.cpp new file mode 100644 index 0000000..d9beae9 --- /dev/null +++ b/databaseview.cpp @@ -0,0 +1,112 @@ +#include "databaseview.h" +#include +#include +#include +#include +#include + +const QStringList DEFAULT_COLUMNS = {"EXPTIME", "OBJECT", "RA", "DEC"}; + +SelectColumnsDialog::SelectColumnsDialog(QWidget *parent) : QDialog(parent) +{ + m_listWidget = new QListWidget(this); + m_listWidget->setSelectionMode(QAbstractItemView::MultiSelection); + QVBoxLayout *layout = new QVBoxLayout(this); + setLayout(layout); + layout->addWidget(m_listWidget); + + QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + layout->addWidget(buttonBox); + + setWindowTitle(tr("Select columns")); +} + +void SelectColumnsDialog::setColumns(QStringList columns) +{ + QSettings settings; + m_listWidget->addItems(columns); + QStringList selected = settings.value("databaseview/selectedColumns", DEFAULT_COLUMNS).toStringList(); + for(auto &sel : selected) + { + int i = columns.indexOf(sel); + if(i>=0) + m_listWidget->item(i)->setSelected(true); + } +} + +QStringList SelectColumnsDialog::selectedColumns() +{ + QStringList ret; + for(auto &sel : m_listWidget->selectedItems()) + ret.append(sel->text()); + return ret; +} + +DataBaseView::DataBaseView(Database *database, QWidget *parent) : QWidget(parent) + ,m_database(database) +{ + QVBoxLayout *layout = new QVBoxLayout(this); + setLayout(layout); + + m_tableView = new QTableView(this); + m_tableView->verticalHeader()->setDefaultSectionSize(1); + layout->addWidget(m_tableView); + + m_model = new QSqlQueryModel(this); + + QSettings settings; + m_tableView->setModel(m_model); + m_tableView->horizontalHeader()->restoreState(settings.value("databaseview/header").toByteArray()); + + QHBoxLayout *hlayout = new QHBoxLayout(this); + layout->addLayout(hlayout); + + QPushButton *selectColumnsButton = new QPushButton(tr("Select columns"), this); + hlayout->addWidget(selectColumnsButton); + connect(selectColumnsButton, &QPushButton::pressed, this, &DataBaseView::selectColumns); + + QPushButton *loadDatabaseButton = new QPushButton(tr("Load database"), this); + hlayout->addWidget(loadDatabaseButton); + connect(loadDatabaseButton, &QPushButton::pressed, this, &DataBaseView::loadDatabase); +} + +DataBaseView::~DataBaseView() +{ + QSettings settings; + settings.setValue("databaseview/header", m_tableView->horizontalHeader()->saveState()); +} + +void DataBaseView::selectColumns() +{ + SelectColumnsDialog dialog; + QStringList columns = m_database->getFitsKeywords(); + dialog.setColumns(columns); + if(dialog.exec() == QDialog::Accepted) + { + QSettings settings; + QStringList columns = dialog.selectedColumns(); + settings.setValue("databaseview/selectedColumns", columns); + prepareQuery(columns); + } +} + +void DataBaseView::loadDatabase() +{ + QSettings settings; + prepareQuery(settings.value("databaseview/selectedColumns", DEFAULT_COLUMNS).toStringList()); +} + +void DataBaseView::prepareQuery(const QStringList &columns) +{ + QString sql = "SELECT file,"; + for(auto &column : columns) + { + sql += QString("GROUP_CONCAT(CASE WHEN key=\"%1\" THEN value END) AS \"%1\",").arg(column); + } + sql.chop(1); + sql += " FROM fits_files LEFT JOIN fits_headers ON fits_files.id=id_file GROUP BY fits_files.id"; + m_model->setQuery(sql); +} + diff --git a/databaseview.h b/databaseview.h new file mode 100644 index 0000000..7ad0d15 --- /dev/null +++ b/databaseview.h @@ -0,0 +1,37 @@ +#ifndef DATABASEVIEW_H +#define DATABASEVIEW_H + +#include +#include +#include +#include +#include +#include "database.h" + +class SelectColumnsDialog : public QDialog +{ + Q_OBJECT + QListWidget *m_listWidget; +public: + SelectColumnsDialog(QWidget *parent = nullptr); + void setColumns(QStringList columns); + QStringList selectedColumns(); +}; + +class DataBaseView : public QWidget +{ + Q_OBJECT + Database *m_database; + QTableView *m_tableView; + QSqlQueryModel *m_model; +public: + explicit DataBaseView(Database *database, QWidget *parent = nullptr); + ~DataBaseView(); +public slots: + void selectColumns(); + void loadDatabase(); +protected: + void prepareQuery(const QStringList &columns); +}; + +#endif // DATABASEVIEW_H diff --git a/mainwindow.cpp b/mainwindow.cpp index a36d27f..124d24f 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -51,6 +51,12 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) m_filesystem = new FilesystemWidget(m_ringList, this); connect(m_filesystem, SIGNAL(fileSelected(int)), this, SLOT(loadFile(int))); + m_database = new Database(this); + if(!m_database->init()) + QMessageBox::critical(this, tr("Can't open DB"), tr("Can't open SQLITE database")); + + m_databaseView = new DataBaseView(m_database, this); + QDockWidget *stretchDock = new QDockWidget(tr("Stretch"), this); stretchDock->setWidget(m_stretchPanel); stretchDock->setObjectName("strechDock"); @@ -61,6 +67,12 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) filesystemDock->setObjectName("filesystemDock"); addDockWidget(Qt::LeftDockWidgetArea, filesystemDock); + QDockWidget *databaseViewDock = new QDockWidget(tr("FITS files database"), this); + databaseViewDock->setWidget(m_databaseView); + databaseViewDock->setObjectName("databaseViewDock"); + databaseViewDock->hide(); + addDockWidget(Qt::RightDockWidgetArea, databaseViewDock); + setWindowTitle(tr("Tenmon")); connect(m_ringList, SIGNAL(pixmapLoaded(Image*)), this, SLOT(pixmapLoaded(Image*))); @@ -118,14 +130,11 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) analyzeMenu->addActions({statsAction, peakAction, starAction}); menuBar()->addMenu(analyzeMenu); - m_database = new Database(this); - if(!m_database->init()) - QMessageBox::critical(this, tr("Can't open DB"), tr("Can't open SQLITE database")); - QMenu *dockMenu = new QMenu(tr("Docks"), this); dockMenu->addAction(infoDock->toggleViewAction()); dockMenu->addAction(stretchDock->toggleViewAction()); dockMenu->addAction(filesystemDock->toggleViewAction()); + dockMenu->addAction(databaseViewDock->toggleViewAction()); menuBar()->addMenu(dockMenu); setupSigterm(); @@ -267,6 +276,13 @@ void MainWindow::loadFile(int row) m_ringList->loadFile(row); } +void MainWindow::indexDir() +{ + QString dir = QFileDialog::getExistingDirectory(this, tr("Index directory"), _lastDir); + if(!dir.isEmpty()) + m_database->indexDir(dir); +} + void MainWindow::saveAs() { QString file = QFileDialog::getSaveFileName(this, tr("Save as"), _lastDir, tr("Images (*.jpg *.png *.JPG *.PNG)")); diff --git a/mainwindow.h b/mainwindow.h index 5e883dc..c9a83e6 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -10,6 +10,7 @@ #include "imagescrollareagl.h" #include "filesystemwidget.h" #include "stretchpanel.h" +#include "databaseview.h" class MainWindow : public QMainWindow { @@ -21,6 +22,7 @@ class MainWindow : public QMainWindow Database *m_database; ImageInfo *m_info; FilesystemWidget *m_filesystem; + DataBaseView *m_databaseView; static int socketPair[2]; QSocketNotifier *socketNotifier; QString _lastDir; @@ -41,6 +43,7 @@ protected slots: void loadFile(); void loadFile(const QString path); void loadFile(int row); + void indexDir(); void saveAs(); void markImage(); void unmarkImage();