Compare commits
4 Commits
ef8b3d7668
...
27afb2ea5f
| Author | SHA1 | Date | |
|---|---|---|---|
| 27afb2ea5f | |||
| 28016ada8d | |||
| 885a5b4c6d | |||
| 63149745ed |
+9
-7
@@ -15,11 +15,13 @@ About::About(QWidget *parent) : QDialog(parent)
|
|||||||
QLabel *label = new QLabel(this);
|
QLabel *label = new QLabel(this);
|
||||||
|
|
||||||
QFile tenmonText(":/about/tenmon");
|
QFile tenmonText(":/about/tenmon");
|
||||||
tenmonText.open(QIODevice::ReadOnly);
|
if(tenmonText.open(QIODevice::ReadOnly))
|
||||||
QByteArray text = tenmonText.readAll();
|
{
|
||||||
text.replace("@GITVERSION@", GITVERSION);
|
QByteArray text = tenmonText.readAll();
|
||||||
label->setText(text);
|
text.replace("@GITVERSION@", GITVERSION);
|
||||||
label->setOpenExternalLinks(true);
|
label->setText(text);
|
||||||
|
label->setOpenExternalLinks(true);
|
||||||
|
}
|
||||||
|
|
||||||
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok);
|
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok);
|
||||||
connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
||||||
@@ -41,8 +43,8 @@ HelpDialog::HelpDialog(QWidget *parent) : QDialog(parent)
|
|||||||
layout->addWidget(helpText);
|
layout->addWidget(helpText);
|
||||||
|
|
||||||
QFile tenmonText(":/help");
|
QFile tenmonText(":/help");
|
||||||
tenmonText.open(QIODevice::ReadOnly);
|
if(tenmonText.open(QIODevice::ReadOnly))
|
||||||
helpText->setHtml(tenmonText.readAll());
|
helpText->setHtml(tenmonText.readAll());
|
||||||
}
|
}
|
||||||
|
|
||||||
QString getVersion()
|
QString getVersion()
|
||||||
|
|||||||
+9
-9
@@ -35,7 +35,7 @@ bool Database::init(const QLatin1String &connectionName)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
qDebug() << "Could not open NGC database";
|
qWarning() << "Could not open NGC database";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,7 +71,7 @@ bool Database::init(const QLatin1String &connectionName)
|
|||||||
}
|
}
|
||||||
if(version > 2)
|
if(version > 2)
|
||||||
{
|
{
|
||||||
qDebug() << "Database version is too new";
|
qWarning() << "Database version is too new";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,16 +100,16 @@ bool Database::init(const QLatin1String &connectionName)
|
|||||||
m_deleteFile.prepare("DELETE FROM fits_files WHERE id=?");
|
m_deleteFile.prepare("DELETE FROM fits_files WHERE id=?");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
qDebug() << error.text();
|
qWarning() << error.text();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
qDebug() << "Failed to open database" << connectionName;
|
qWarning() << "Failed to open database" << connectionName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
qDebug() << "Database is invalid";
|
qWarning() << "Database is invalid";
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -175,7 +175,7 @@ bool Database::checkError(QSqlQuery &query)
|
|||||||
return true;
|
return true;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
qDebug() << error.text();
|
qWarning() << error.text();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -383,7 +383,7 @@ bool Database::indexFile(const QFileInfo &file)
|
|||||||
m_insertFileWcs.bindValue(7, crVal2);
|
m_insertFileWcs.bindValue(7, crVal2);
|
||||||
if(!m_insertFileWcs.exec())
|
if(!m_insertFileWcs.exec())
|
||||||
{
|
{
|
||||||
qDebug() << "Database error" << m_insertFileWcs.lastError();
|
qWarning() << "Database error" << m_insertFileWcs.lastError();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
last_id = m_insertFileWcs.lastInsertId().toLongLong();
|
last_id = m_insertFileWcs.lastInsertId().toLongLong();
|
||||||
@@ -394,7 +394,7 @@ bool Database::indexFile(const QFileInfo &file)
|
|||||||
m_insertFile.bindValue(1, mtime);
|
m_insertFile.bindValue(1, mtime);
|
||||||
if(!m_insertFile.exec())
|
if(!m_insertFile.exec())
|
||||||
{
|
{
|
||||||
qDebug() << "Database error" << m_insertFile.lastError();
|
qWarning() << "Database error" << m_insertFile.lastError();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
last_id = m_insertFile.lastInsertId().toLongLong();
|
last_id = m_insertFile.lastInsertId().toLongLong();
|
||||||
@@ -415,7 +415,7 @@ bool Database::indexFile(const QFileInfo &file)
|
|||||||
m_insertFitsHeader.bindValue(3, comments);
|
m_insertFitsHeader.bindValue(3, comments);
|
||||||
if(!m_insertFitsHeader.execBatch())
|
if(!m_insertFitsHeader.execBatch())
|
||||||
{
|
{
|
||||||
qDebug() << "Database error" << m_insertFitsHeader.lastError();
|
qWarning() << "Database error" << m_insertFitsHeader.lastError();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+181
-24
@@ -1,20 +1,31 @@
|
|||||||
#include "databasetree.h"
|
#include "databasetree.h"
|
||||||
|
|
||||||
#include "database.h"
|
#include "database.h"
|
||||||
|
#include "databaseview.h"
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
#include <QDialogButtonBox>
|
#include <QDialogButtonBox>
|
||||||
|
#include <QLabel>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QSqlError>
|
#include <QSqlError>
|
||||||
|
#include <QStackedWidget>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
DatabaseTreeSettings::DatabaseTreeSettings(const QString &filter, const QStringList &keywords, QWidget *parent) : QDialog(parent)
|
DatabaseTreeSettings::DatabaseTreeSettings(const QStringList &data, QStringList keywords, QWidget *parent) : QDialog(parent)
|
||||||
{
|
{
|
||||||
setWindowTitle(tr("Add tree filter"));
|
setWindowTitle(tr("Add tree filter"));
|
||||||
QVBoxLayout *vlayout = new QVBoxLayout(this);
|
QVBoxLayout *vlayout = new QVBoxLayout(this);
|
||||||
setLayout(vlayout);
|
setLayout(vlayout);
|
||||||
|
|
||||||
QStringList key = filter.split('/');
|
QStringList key = data[0].split('/');
|
||||||
|
|
||||||
|
qsizetype dateobsindex = keywords.indexOf("DATE-OBS");
|
||||||
|
if(dateobsindex != -1)
|
||||||
|
{
|
||||||
|
keywords.insert(dateobsindex + 1, "DATE-OBS_YEAR-MONTH-DAY");
|
||||||
|
keywords.insert(dateobsindex + 1, "DATE-OBS_YEAR-MONTH");
|
||||||
|
keywords.insert(dateobsindex + 1, "DATE-OBS_YEAR");
|
||||||
|
}
|
||||||
|
|
||||||
for(int i = 0; i < 10; i++)
|
for(int i = 0; i < 10; i++)
|
||||||
{
|
{
|
||||||
@@ -27,8 +38,15 @@ DatabaseTreeSettings::DatabaseTreeSettings(const QString &filter, const QStringL
|
|||||||
comboxBox->setCurrentText(key[i]);
|
comboxBox->setCurrentText(key[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vlayout->addWidget(new QLabel(tr("Aggregate function"), this));
|
||||||
|
_aggregateFunction = new QComboBox(this);
|
||||||
|
_aggregateFunction->addItems({"", "SUM", "COUNT", "AVG", "MIN", "MAX", "MEDIAN"});
|
||||||
|
vlayout->addWidget(_aggregateFunction);
|
||||||
|
_aggregateFunction->setToolTip(tr("This aggregate function will be applied to last level of grouping"));
|
||||||
|
_aggregateFunction->setCurrentText(data[1]);
|
||||||
|
|
||||||
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
|
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
|
||||||
connect(buttonBox, &QDialogButtonBox::accepted, this, &DatabaseTreeSettings::accept);
|
connect(buttonBox, &QDialogButtonBox::accepted, this, &DatabaseTreeSettings::acceptButton);
|
||||||
connect(buttonBox, &QDialogButtonBox::rejected, this, &DatabaseTreeSettings::reject);
|
connect(buttonBox, &QDialogButtonBox::rejected, this, &DatabaseTreeSettings::reject);
|
||||||
vlayout->addWidget(buttonBox);
|
vlayout->addWidget(buttonBox);
|
||||||
}
|
}
|
||||||
@@ -44,6 +62,24 @@ QString DatabaseTreeSettings::keywords() const
|
|||||||
return keywords.join('/');
|
return keywords.join('/');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString DatabaseTreeSettings::aggregrationFunc() const
|
||||||
|
{
|
||||||
|
return _aggregateFunction->currentText();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DatabaseTreeSettings::acceptButton()
|
||||||
|
{
|
||||||
|
for(QComboBox *box : _keywordsSelect)
|
||||||
|
{
|
||||||
|
if(box->currentIndex() > 0)
|
||||||
|
{
|
||||||
|
QDialog::accept();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QDialog::reject();
|
||||||
|
}
|
||||||
|
|
||||||
class TreeNode
|
class TreeNode
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -130,6 +166,11 @@ void DatabaseTree::setKeys(const QStringList &keys)
|
|||||||
endResetModel();
|
endResetModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QStringList DatabaseTree::keys() const
|
||||||
|
{
|
||||||
|
return _keys;
|
||||||
|
}
|
||||||
|
|
||||||
QModelIndex DatabaseTree::index(int row, int column, const QModelIndex &parent) const
|
QModelIndex DatabaseTree::index(int row, int column, const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
if(!hasIndex(row, column, parent))
|
if(!hasIndex(row, column, parent))
|
||||||
@@ -262,6 +303,51 @@ void DatabaseTree::load()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QSqlQuery DatabaseTree::getGroupQuery(const QString &aggregateFunc) const
|
||||||
|
{
|
||||||
|
QStringList cols;
|
||||||
|
QString join;
|
||||||
|
QString sum;
|
||||||
|
|
||||||
|
for(int i = 0; i < _keys.size(); i++)
|
||||||
|
{
|
||||||
|
join += QString(" LEFT JOIN fits_headers AS h%1 ON f.id = h%1.id_file AND h%1.key = ?").arg(i);
|
||||||
|
if(_keys[i] == "DATE-OBS_YEAR")
|
||||||
|
cols.append(QString("STRFTIME('%Y', h%1.value)").arg(i));
|
||||||
|
else if(_keys[i] == "DATE-OBS_YEAR-MONTH")
|
||||||
|
cols.append(QString("STRFTIME('%Y-%m', h%1.value)").arg(i));
|
||||||
|
else if(_keys[i] == "DATE-OBS_YEAR-MONTH-DAY")
|
||||||
|
cols.append(QString("STRFTIME('%Y-%m-%d', h%1.value)").arg(i));
|
||||||
|
else
|
||||||
|
cols.append(QString("h%1.value").arg(i));
|
||||||
|
|
||||||
|
if(i == _keys.size() - 1)
|
||||||
|
{
|
||||||
|
QString tmp = aggregateFunc + "(" + cols.last() + ")";
|
||||||
|
cols.last() = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList group = cols;
|
||||||
|
group.removeLast();
|
||||||
|
QString sql = "SELECT " + cols.join(',') + " FROM fits_files AS f" + join + " GROUP BY " + group.join(',');
|
||||||
|
|
||||||
|
QSqlQuery query(sql, _database->db());
|
||||||
|
for(auto &val : _keys)
|
||||||
|
{
|
||||||
|
if(val.startsWith("DATE-OBS_"))
|
||||||
|
query.addBindValue("DATE-OBS");
|
||||||
|
else
|
||||||
|
query.addBindValue(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug() << "Group query" << sql;
|
||||||
|
if(!query.exec())
|
||||||
|
qWarning() << "Group query failed" << query.lastError();
|
||||||
|
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
|
||||||
void DatabaseTree::prepareQueries()
|
void DatabaseTree::prepareQueries()
|
||||||
{
|
{
|
||||||
if(!_loaded)return;
|
if(!_loaded)return;
|
||||||
@@ -276,22 +362,42 @@ void DatabaseTree::prepareQueries()
|
|||||||
|
|
||||||
for(int i = 0; i < _keys.size(); i++)
|
for(int i = 0; i < _keys.size(); i++)
|
||||||
{
|
{
|
||||||
QString sql = QString("SELECT h%1.value FROM fits_files AS f").arg(i) + join + where + QString(" GROUP BY h%1.value ORDER BY h%1.value").arg(i);
|
QString sql;
|
||||||
qDebug() << _keys[i] << sql;
|
QString col = QString("h%1.value").arg(i);
|
||||||
|
if(_keys[i] == "DATE-OBS_YEAR")
|
||||||
|
col = QString("STRFTIME('%Y', h%1.value)").arg(i);
|
||||||
|
else if(_keys[i] == "DATE-OBS_YEAR-MONTH")
|
||||||
|
col = QString("STRFTIME('%Y-%m', h%1.value)").arg(i);
|
||||||
|
else if(_keys[i] == "DATE-OBS_YEAR-MONTH-DAY")
|
||||||
|
col = QString("STRFTIME('%Y-%m-%d', h%1.value)").arg(i);
|
||||||
|
|
||||||
|
sql = QString("SELECT %1 FROM fits_files AS f").arg(col) + join + where + QString(" GROUP BY %1 ORDER BY %1").arg(col);
|
||||||
|
|
||||||
|
qDebug() << "Tree query for" << _keys[i] << sql;
|
||||||
QSqlQuery query(sql, _database->db());
|
QSqlQuery query(sql, _database->db());
|
||||||
for(auto &val : _keys)
|
for(auto &val : _keys)
|
||||||
query.addBindValue(val);
|
{
|
||||||
|
if(val.startsWith("DATE-OBS_"))
|
||||||
|
query.addBindValue("DATE-OBS");
|
||||||
|
else
|
||||||
|
query.addBindValue(val);
|
||||||
|
}
|
||||||
|
|
||||||
if(where.isEmpty())
|
if(where.isEmpty())
|
||||||
where += QString(" WHERE h%1.value IS ?").arg(i);
|
where += QString(" WHERE %1 IS ?").arg(col);
|
||||||
else
|
else
|
||||||
where += QString(" AND h%1.value IS ?").arg(i);
|
where += QString(" AND %1 IS ?").arg(col);
|
||||||
_queries.append(std::move(query));
|
_queries.append(std::move(query));
|
||||||
}
|
}
|
||||||
|
|
||||||
QSqlQuery files("SELECT f.file FROM fits_files AS f " + join + where + " GROUP BY f.id ORDER BY f.file", _database->db());
|
QSqlQuery files("SELECT f.file FROM fits_files AS f" + join + where + " GROUP BY f.id ORDER BY f.file", _database->db());
|
||||||
for(auto &val : _keys)
|
for(auto &val : _keys)
|
||||||
files.addBindValue(val);
|
{
|
||||||
|
if(val.startsWith("DATE-OBS_"))
|
||||||
|
files.addBindValue("DATE-OBS");
|
||||||
|
else
|
||||||
|
files.addBindValue(val);
|
||||||
|
}
|
||||||
qDebug() << files.lastQuery();
|
qDebug() << files.lastQuery();
|
||||||
_queries.append(std::move(files));
|
_queries.append(std::move(files));
|
||||||
}
|
}
|
||||||
@@ -322,7 +428,7 @@ void DatabaseTree::fillNode(TreeNode *node)
|
|||||||
q.bindValue(i + _keys.size(), vals[i]);
|
q.bindValue(i + _keys.size(), vals[i]);
|
||||||
if(!q.exec())
|
if(!q.exec())
|
||||||
{
|
{
|
||||||
qWarning() << "Failed to execute query" << q.lastError();
|
qWarning() << "Failed to execute query" << q.lastError() << q.lastQuery() << q.boundValues();
|
||||||
node->fill({});
|
node->fill({});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -345,25 +451,44 @@ DatabaseTreeView::DatabaseTreeView(Database *database, QWidget *parent) : QWidge
|
|||||||
_treeView->setModel(_model);
|
_treeView->setModel(_model);
|
||||||
_treeView->setHeaderHidden(true);
|
_treeView->setHeaderHidden(true);
|
||||||
|
|
||||||
|
_tableView = new CopyTableView(this);
|
||||||
|
_sqlModel = new QSqlQueryModel(this);
|
||||||
|
_tableView->setModel(_sqlModel);
|
||||||
|
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
QStringList filters = settings.value("databasetreeview/filters", QStringList{"OBJECT", "OBJECT/IMAGETYP", "OBJECT/IMAGETYP/FILTER", "OBJECT/IMAGETYP/FILTER/EXPTIME", "IMAGETYP/OBJECT/IMAGETYP/FILTER/EXPTIME"}).toStringList();
|
QStringList filters = settings.value("databasetreeview/filters", QStringList{"OBJECT", "OBJECT/IMAGETYP", "OBJECT/IMAGETYP/FILTER", "OBJECT/IMAGETYP/FILTER/EXPTIME",
|
||||||
|
"IMAGETYP/OBJECT/IMAGETYP/FILTER/EXPTIME", "IMAGETYP/DATE-OBS_YEAR/EXPTIME"}).toStringList();
|
||||||
|
QStringList aggrFuncs = settings.value("databasetreeview/aggrFuncs", QStringList{"", "", "", "SUM", "SUM", "SUM"}).toStringList();
|
||||||
int selectedFilter = settings.value("databasetreeview/selectedFilter", 2).toInt();
|
int selectedFilter = settings.value("databasetreeview/selectedFilter", 2).toInt();
|
||||||
|
|
||||||
_filters = new QComboBox(this);
|
_filters = new QComboBox(this);
|
||||||
_filters->addItems(filters);
|
for(int i = 0; i < std::min(filters.size(), aggrFuncs.size()); i++)
|
||||||
|
{
|
||||||
|
_filters->addItem(filters[i] + " " + aggrFuncs[i], QStringList{filters[i], aggrFuncs[i]});
|
||||||
|
}
|
||||||
_filters->setCurrentIndex(selectedFilter);
|
_filters->setCurrentIndex(selectedFilter);
|
||||||
connect(_filters, &QComboBox::currentTextChanged, this, &DatabaseTreeView::filterChanged);
|
connect(_filters, &QComboBox::currentIndexChanged, this, &DatabaseTreeView::filterChanged);
|
||||||
filterChanged(_filters->currentText());
|
filterChanged(_filters->currentIndex());
|
||||||
|
|
||||||
|
QStackedWidget *stackedWidget = new QStackedWidget;
|
||||||
|
stackedWidget->addWidget(_treeView);
|
||||||
|
stackedWidget->addWidget(_tableView);
|
||||||
|
|
||||||
QPushButton *addButton = new QPushButton(tr("Add"), this);
|
QPushButton *addButton = new QPushButton(tr("Add"), this);
|
||||||
QPushButton *removeButton = new QPushButton(tr("Remove"), this);
|
QPushButton *removeButton = new QPushButton(tr("Remove"), this);
|
||||||
|
QPushButton *treeTableButton = new QPushButton(tr("Tree/Table"), this);
|
||||||
|
treeTableButton->setCheckable(true);
|
||||||
|
connect(treeTableButton, &QPushButton::clicked, [stackedWidget](bool checked){
|
||||||
|
stackedWidget->setCurrentIndex(checked ? 1 : 0);
|
||||||
|
});
|
||||||
|
|
||||||
hlayout->addWidget(_filters, 1);
|
hlayout->addWidget(_filters, 1);
|
||||||
hlayout->addWidget(addButton);
|
hlayout->addWidget(addButton);
|
||||||
hlayout->addWidget(removeButton);
|
hlayout->addWidget(removeButton);
|
||||||
|
hlayout->addWidget(treeTableButton);
|
||||||
|
|
||||||
vlayout->addLayout(hlayout);
|
vlayout->addLayout(hlayout);
|
||||||
vlayout->addWidget(_treeView);
|
vlayout->addWidget(stackedWidget);
|
||||||
|
|
||||||
connect(_treeView, &QTreeView::activated, [this](const QModelIndex &index){
|
connect(_treeView, &QTreeView::activated, [this](const QModelIndex &index){
|
||||||
if(!_model->hasChildren(index))
|
if(!_model->hasChildren(index))
|
||||||
@@ -380,27 +505,36 @@ DatabaseTreeView::DatabaseTreeView(Database *database, QWidget *parent) : QWidge
|
|||||||
DatabaseTreeView::~DatabaseTreeView()
|
DatabaseTreeView::~DatabaseTreeView()
|
||||||
{
|
{
|
||||||
QStringList filters;
|
QStringList filters;
|
||||||
|
QStringList aggrFuncs;
|
||||||
for(int i = 0; i < _filters->count(); i++)
|
for(int i = 0; i < _filters->count(); i++)
|
||||||
filters.append(_filters->itemText(i));
|
{
|
||||||
|
QStringList data = _filters->itemData(i).toStringList();
|
||||||
|
filters.append(data[0]);
|
||||||
|
aggrFuncs.append(data[1]);
|
||||||
|
}
|
||||||
|
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
settings.setValue("databasetreeview/filters", filters);
|
settings.setValue("databasetreeview/filters", filters);
|
||||||
|
settings.setValue("databasetreeview/aggrFuncs", aggrFuncs);
|
||||||
settings.setValue("databasetreeview/selectedFilter", _filters->currentIndex());
|
settings.setValue("databasetreeview/selectedFilter", _filters->currentIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatabaseTreeView::addFilter()
|
void DatabaseTreeView::addFilter()
|
||||||
{
|
{
|
||||||
QStringList keywords = _database->getFitsKeywords();
|
QStringList keywords = _database->getFitsKeywords();
|
||||||
DatabaseTreeSettings settings(_filters->currentText(), keywords, this);
|
QStringList data = _filters->currentData().toStringList();
|
||||||
|
DatabaseTreeSettings settings(data, keywords, this);
|
||||||
int result = settings.exec();
|
int result = settings.exec();
|
||||||
if(result == QDialog::Accepted)
|
if(result == QDialog::Accepted)
|
||||||
{
|
{
|
||||||
QString keywords = settings.keywords();
|
QString keywords = settings.keywords();
|
||||||
int idx = _filters->findText(keywords);
|
QString aggrFunc = settings.aggregrationFunc();
|
||||||
|
QString text = keywords + " " + aggrFunc;
|
||||||
|
int idx = _filters->findText(text);
|
||||||
if(idx == -1)
|
if(idx == -1)
|
||||||
{
|
{
|
||||||
_filters->addItem(keywords);
|
_filters->addItem(text, QStringList{keywords, aggrFunc});
|
||||||
_filters->setCurrentText(keywords);
|
_filters->setCurrentText(text);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -415,14 +549,37 @@ void DatabaseTreeView::removeFilter()
|
|||||||
_filters->removeItem(_filters->currentIndex());
|
_filters->removeItem(_filters->currentIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatabaseTreeView::filterChanged(const QString &filter)
|
void DatabaseTreeView::filterChanged(int index)
|
||||||
{
|
{
|
||||||
QStringList keys = filter.split('/');
|
QStringList data = _filters->itemData(index).toStringList();
|
||||||
|
QStringList keys = data[0].split('/');
|
||||||
_model->setKeys(keys);
|
_model->setKeys(keys);
|
||||||
|
setQuery(data[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatabaseTreeView::visible(bool visible)
|
void DatabaseTreeView::visible(bool visible)
|
||||||
{
|
{
|
||||||
if(visible)
|
if(visible && !_loaded)
|
||||||
|
{
|
||||||
|
_loaded = true;
|
||||||
_model->load();
|
_model->load();
|
||||||
|
QStringList data = _filters->currentData().toStringList();
|
||||||
|
setQuery(data[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DatabaseTreeView::setQuery(const QString &func)
|
||||||
|
{
|
||||||
|
QStringList keys = _model->keys();
|
||||||
|
int i = 0;
|
||||||
|
_sqlModel->setQuery(_model->getGroupQuery(func));
|
||||||
|
if(!func.isEmpty())
|
||||||
|
{
|
||||||
|
QString tmp = func + "(" + keys.last() + ")";
|
||||||
|
keys.last() = tmp;
|
||||||
|
}
|
||||||
|
for(auto &key : keys)
|
||||||
|
_sqlModel->setHeaderData(i++, Qt::Horizontal, key);
|
||||||
|
|
||||||
|
_tableView->resizeColumnsToContents();
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-6
@@ -2,11 +2,13 @@
|
|||||||
#define DATABASETREE_H
|
#define DATABASETREE_H
|
||||||
|
|
||||||
#include <QAbstractItemModel>
|
#include <QAbstractItemModel>
|
||||||
#include <QTreeView>
|
|
||||||
#include <QSqlQuery>
|
|
||||||
#include <QFont>
|
|
||||||
#include <QDialog>
|
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QFont>
|
||||||
|
#include <QSqlQuery>
|
||||||
|
#include <QSqlQueryModel>
|
||||||
|
#include <QTableView>
|
||||||
|
#include <QTreeView>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
class Database;
|
class Database;
|
||||||
@@ -14,11 +16,16 @@ class TreeNode;
|
|||||||
|
|
||||||
class DatabaseTreeSettings : public QDialog
|
class DatabaseTreeSettings : public QDialog
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit DatabaseTreeSettings(const QString &filter, const QStringList &keywords, QWidget *parent = nullptr);
|
explicit DatabaseTreeSettings(const QStringList &data, QStringList keywords, QWidget *parent = nullptr);
|
||||||
QString keywords() const;
|
QString keywords() const;
|
||||||
|
QString aggregrationFunc() const;
|
||||||
|
public slots:
|
||||||
|
void acceptButton();
|
||||||
private:
|
private:
|
||||||
QVector<QComboBox*> _keywordsSelect;
|
QVector<QComboBox*> _keywordsSelect;
|
||||||
|
QComboBox *_aggregateFunction;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DatabaseTree : public QAbstractItemModel
|
class DatabaseTree : public QAbstractItemModel
|
||||||
@@ -26,6 +33,7 @@ class DatabaseTree : public QAbstractItemModel
|
|||||||
public:
|
public:
|
||||||
explicit DatabaseTree(Database *database, QObject *parent = nullptr);
|
explicit DatabaseTree(Database *database, QObject *parent = nullptr);
|
||||||
void setKeys(const QStringList &keys);
|
void setKeys(const QStringList &keys);
|
||||||
|
QStringList keys() const;
|
||||||
QModelIndex index(int row, int column, const QModelIndex &parent) const override;
|
QModelIndex index(int row, int column, const QModelIndex &parent) const override;
|
||||||
QModelIndex parent(const QModelIndex &index) const override;
|
QModelIndex parent(const QModelIndex &index) const override;
|
||||||
int rowCount(const QModelIndex &index) const override;
|
int rowCount(const QModelIndex &index) const override;
|
||||||
@@ -35,6 +43,7 @@ public:
|
|||||||
void fetchMore(const QModelIndex &parent) override;
|
void fetchMore(const QModelIndex &parent) override;
|
||||||
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
|
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
|
||||||
void load();
|
void load();
|
||||||
|
QSqlQuery getGroupQuery(const QString &aggregateFunc) const;
|
||||||
private:
|
private:
|
||||||
void prepareQueries();
|
void prepareQueries();
|
||||||
void fillNode(TreeNode *node);
|
void fillNode(TreeNode *node);
|
||||||
@@ -55,15 +64,20 @@ public:
|
|||||||
public slots:
|
public slots:
|
||||||
void addFilter();
|
void addFilter();
|
||||||
void removeFilter();
|
void removeFilter();
|
||||||
void filterChanged(const QString &filter);
|
void filterChanged(int index);
|
||||||
void visible(bool visible);
|
void visible(bool visible);
|
||||||
|
private:
|
||||||
|
void setQuery(const QString &func);
|
||||||
signals:
|
signals:
|
||||||
void loadFile(const QString &file);
|
void loadFile(const QString &file);
|
||||||
private:
|
private:
|
||||||
QComboBox *_filters = nullptr;
|
QComboBox *_filters = nullptr;
|
||||||
QTreeView *_treeView = nullptr;
|
QTreeView *_treeView = nullptr;
|
||||||
|
QTableView *_tableView = nullptr;
|
||||||
DatabaseTree *_model = nullptr;
|
DatabaseTree *_model = nullptr;
|
||||||
|
QSqlQueryModel *_sqlModel = nullptr;
|
||||||
Database *_database = nullptr;
|
Database *_database = nullptr;
|
||||||
|
bool _loaded = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // DATABASETREE_H
|
#endif // DATABASETREE_H
|
||||||
|
|||||||
+37
-2
@@ -239,7 +239,8 @@ void FITSFileModel::prepareQuery()
|
|||||||
|
|
||||||
if(!query.exec())
|
if(!query.exec())
|
||||||
qWarning() << "Failed to exectute query" << query.lastQuery() << bindValuesJoin << bindValues;
|
qWarning() << "Failed to exectute query" << query.lastQuery() << bindValuesJoin << bindValues;
|
||||||
setQuery(std::move(query));
|
else
|
||||||
|
setQuery(std::move(query));
|
||||||
|
|
||||||
setHeaderData(0, Qt::Horizontal, tr("File name"));
|
setHeaderData(0, Qt::Horizontal, tr("File name"));
|
||||||
i = 1;
|
i = 1;
|
||||||
@@ -255,7 +256,7 @@ void FITSFileModel::prepareQuery()
|
|||||||
m_markedFiles = QSet<QString>(list.begin(), list.end());
|
m_markedFiles = QSet<QString>(list.begin(), list.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
DatabaseTableView::DatabaseTableView(QWidget *parent) : QTableView(parent)
|
DatabaseTableView::DatabaseTableView(QWidget *parent) : CopyTableView(parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -498,3 +499,37 @@ void DataBaseView::visible(bool visible)
|
|||||||
{
|
{
|
||||||
if(visible)m_model->load();
|
if(visible)m_model->load();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CopyTableView::CopyTableView(QWidget *parent) : QTableView(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CopyTableView::keyPressEvent(QKeyEvent *event)
|
||||||
|
{
|
||||||
|
if(event->matches(QKeySequence::Copy))
|
||||||
|
{
|
||||||
|
QModelIndexList list = selectedIndexes();
|
||||||
|
QString table;
|
||||||
|
if(list.size() == 0)return;
|
||||||
|
|
||||||
|
int row = list.first().row();
|
||||||
|
int col = list.first().column();
|
||||||
|
for(auto &index : list)
|
||||||
|
{
|
||||||
|
if(row != index.row())
|
||||||
|
table.append('\n');
|
||||||
|
else if(col != index.column())
|
||||||
|
table.append('\t');
|
||||||
|
|
||||||
|
table.append(index.data().toString());
|
||||||
|
row = index.row();
|
||||||
|
col = index.column();
|
||||||
|
}
|
||||||
|
qApp->clipboard()->setText(table);
|
||||||
|
event->accept();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QTableView::keyPressEvent(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+9
-1
@@ -44,7 +44,15 @@ protected:
|
|||||||
void prepareQuery();
|
void prepareQuery();
|
||||||
};
|
};
|
||||||
|
|
||||||
class DatabaseTableView : public QTableView
|
class CopyTableView : public QTableView
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit CopyTableView(QWidget *parent = nullptr);
|
||||||
|
void keyPressEvent(QKeyEvent *event);
|
||||||
|
};
|
||||||
|
|
||||||
|
class DatabaseTableView : public CopyTableView
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
|||||||
+10
-6
@@ -345,18 +345,22 @@ Download::Download(QNetworkReply *reply, const QString indexPath, QObject *paren
|
|||||||
filename.remove(QRegularExpression("\\.zst$"));
|
filename.remove(QRegularExpression("\\.zst$"));
|
||||||
|
|
||||||
_fw.setFileName(indexPath + "/" + filename);
|
_fw.setFileName(indexPath + "/" + filename);
|
||||||
_fw.open(QIODevice::WriteOnly | QIODevice::Truncate);
|
if(_fw.open(QIODevice::WriteOnly | QIODevice::Truncate))
|
||||||
if(_fw.isOpen())
|
|
||||||
{
|
{
|
||||||
qDebug() << "open file" << _fw.fileName();
|
qDebug() << "open file" << _fw.fileName();
|
||||||
|
_dstream = ZSTD_createDStream();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qWarning() << "Failed to open file" << _fw.fileName();
|
||||||
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
_dstream = ZSTD_createDStream();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Download::~Download()
|
Download::~Download()
|
||||||
{
|
{
|
||||||
ZSTD_freeDStream(_dstream);
|
if(_dstream)
|
||||||
|
ZSTD_freeDStream(_dstream);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Download::abort()
|
void Download::abort()
|
||||||
@@ -402,7 +406,7 @@ void Download::finished()
|
|||||||
|
|
||||||
void Download::decompress(QByteArray &data)
|
void Download::decompress(QByteArray &data)
|
||||||
{
|
{
|
||||||
if(data.isEmpty())return;
|
if(data.isEmpty() || _dstream == nullptr)return;
|
||||||
|
|
||||||
_hash.addData(data);
|
_hash.addData(data);
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,8 @@
|
|||||||
class Download : public QObject
|
class Download : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
QNetworkReply *_reply;
|
QNetworkReply *_reply = nullptr;
|
||||||
ZSTD_DStream *_dstream;
|
ZSTD_DStream *_dstream = nullptr;
|
||||||
QFile _fw;
|
QFile _fw;
|
||||||
QCryptographicHash _hash;
|
QCryptographicHash _hash;
|
||||||
public:
|
public:
|
||||||
|
|||||||
+6
-6
@@ -154,7 +154,7 @@ void ImageWidgetGL::setImage(std::shared_ptr<RawImage> image, int index)
|
|||||||
m_image->bind();
|
m_image->bind();
|
||||||
f->glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
|
f->glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
|
||||||
f->glGenerateMipmap(GL_TEXTURE_2D);
|
f->glGenerateMipmap(GL_TEXTURE_2D);
|
||||||
qDebug() << "setImage" << timer.elapsed();
|
qDebug() << "ImageWidgetGL::setImage" << timer.elapsed() << "ms";
|
||||||
m_swPaint = f->glGetError() != GL_NO_ERROR;
|
m_swPaint = f->glGetError() != GL_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -721,19 +721,19 @@ void ImageWidgetGL::initializeGL()
|
|||||||
logger->startLogging();
|
logger->startLogging();
|
||||||
connect(logger, &QOpenGLDebugLogger::messageLogged, [](const QOpenGLDebugMessage &message)
|
connect(logger, &QOpenGLDebugLogger::messageLogged, [](const QOpenGLDebugMessage &message)
|
||||||
{
|
{
|
||||||
qDebug() << message;
|
qDebug() << "OpenGL debug" << message;
|
||||||
});
|
});
|
||||||
|
|
||||||
qDebug() << "Vendor:" << (char*)f->glGetString(GL_VENDOR);
|
qDebug() << "OpenGL Vendor:" << (char*)f->glGetString(GL_VENDOR);
|
||||||
qDebug() << "Renderer:" << (char*)f->glGetString(GL_RENDERER);
|
qDebug() << "OpenGL Renderer:" << (char*)f->glGetString(GL_RENDERER);
|
||||||
qDebug() << "Version:" << (char*)f->glGetString(GL_VERSION);
|
qDebug() << "OpenGL Version:" << (char*)f->glGetString(GL_VERSION);
|
||||||
f->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_maxTextureSize);
|
f->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_maxTextureSize);
|
||||||
f->glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &m_maxArrayLayers);
|
f->glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &m_maxArrayLayers);
|
||||||
qDebug() << "Max texture size:" << m_maxTextureSize << "max layers:" << m_maxArrayLayers;
|
qDebug() << "Max texture size:" << m_maxTextureSize << "max layers:" << m_maxArrayLayers;
|
||||||
|
|
||||||
//MANUAL_MIPMAP_GEN = QString((const char*)f->glGetString(GL_VENDOR)).startsWith("ATI Technologies Inc", Qt::CaseInsensitive);
|
//MANUAL_MIPMAP_GEN = QString((const char*)f->glGetString(GL_VENDOR)).startsWith("ATI Technologies Inc", Qt::CaseInsensitive);
|
||||||
|
|
||||||
qDebug() << context()->format();
|
qDebug() << "OpenGL context format" << context()->format();
|
||||||
|
|
||||||
// each vertex is x,y 2D position and s,t texture coordinates
|
// each vertex is x,y 2D position and s,t texture coordinates
|
||||||
float vertexs[] = {-1.0f, -1.0f, 0.0f, 1.0f,
|
float vertexs[] = {-1.0f, -1.0f, 0.0f, 1.0f,
|
||||||
|
|||||||
+7
-7
@@ -95,7 +95,7 @@ bool loadFITS(const QString path, ImageInfoData &info, std::shared_ptr<RawImage>
|
|||||||
char err[100];
|
char err[100];
|
||||||
fits_get_errstatus(status, err);
|
fits_get_errstatus(status, err);
|
||||||
info.info.append({QObject::tr("Error"), QString(err)});
|
info.info.append({QObject::tr("Error"), QString(err)});
|
||||||
qDebug() << "Failed to load FITS file" << err;
|
qWarning() << "Failed to load FITS file" << err;
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -335,7 +335,7 @@ bool loadXISF(const QString &path, ImageInfoData &info, std::shared_ptr<RawImage
|
|||||||
catch (LibXISF::Error &err)
|
catch (LibXISF::Error &err)
|
||||||
{
|
{
|
||||||
info.info.append(QPair<QString, QString>("Error", err.what()));
|
info.info.append(QPair<QString, QString>("Error", err.what()));
|
||||||
qDebug() << "Failed to load XISF" << err.what();
|
qWarning() << "Failed to load XISF" << err.what();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
info.info.append({QObject::tr("Error"), QObject::tr("Unsupported sample format")});
|
info.info.append({QObject::tr("Error"), QObject::tr("Unsupported sample format")});
|
||||||
@@ -382,7 +382,7 @@ bool readXISFHeader(const QString &path, ImageInfoData &info)
|
|||||||
}
|
}
|
||||||
catch (LibXISF::Error &err)
|
catch (LibXISF::Error &err)
|
||||||
{
|
{
|
||||||
qDebug() << err.what();
|
qWarning() << "LibXISF error" << err.what();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -455,17 +455,17 @@ bool loadImage(const QString &path, ImageInfoData &info, std::shared_ptr<RawImag
|
|||||||
if(path.endsWith(".CR2", Qt::CaseInsensitive) || path.endsWith(".CR3", Qt::CaseInsensitive) || path.endsWith(".NEF", Qt::CaseInsensitive) || path.endsWith(".DNG", Qt::CaseInsensitive))
|
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);
|
ret = loadRAW(path, info, rawImage);
|
||||||
qDebug() << "LoadRAW" << timer.elapsed();
|
qDebug() << "LoadRAW" << timer.elapsed() << "ms";
|
||||||
}
|
}
|
||||||
else if(isFITS(fileInfo.suffix()))
|
else if(isFITS(fileInfo.suffix()))
|
||||||
{
|
{
|
||||||
ret = loadFITS(path, info, rawImage, planar, index);
|
ret = loadFITS(path, info, rawImage, planar, index);
|
||||||
qDebug() << "LoadFITS" << timer.elapsed();
|
qDebug() << "LoadFITS" << timer.elapsed() << "ms";
|
||||||
}
|
}
|
||||||
else if(isXISF(fileInfo.suffix()))
|
else if(isXISF(fileInfo.suffix()))
|
||||||
{
|
{
|
||||||
ret = loadXISF(path, info, rawImage, planar, index);
|
ret = loadXISF(path, info, rawImage, planar, index);
|
||||||
qDebug() << "LoadXISF" << timer.elapsed();
|
qDebug() << "LoadXISF" << timer.elapsed() << "ms";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -481,7 +481,7 @@ bool loadImage(const QString &path, ImageInfoData &info, std::shared_ptr<RawImag
|
|||||||
exif_data_free(exif);
|
exif_data_free(exif);
|
||||||
}
|
}
|
||||||
rawImage = std::make_shared<RawImage>(img);
|
rawImage = std::make_shared<RawImage>(img);
|
||||||
qDebug() << "LoadQImage" << timer.elapsed();
|
qDebug() << "LoadQImage" << timer.elapsed() << "ms";
|
||||||
ret = !img.isNull();
|
ret = !img.isNull();
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
+1
-1
@@ -835,7 +835,7 @@ void MainWindow::checkNewVersion()
|
|||||||
if(QMessageBox::question(this, tr("Update check"), tr("New version %1 is available. Do you want to download it now?").arg(tag)) == QMessageBox::Yes)
|
if(QMessageBox::question(this, tr("Update check"), tr("New version %1 is available. Do you want to download it now?").arg(tag)) == QMessageBox::Yes)
|
||||||
{
|
{
|
||||||
QUrl url(json.object().value("html_url").toString());
|
QUrl url(json.object().value("html_url").toString());
|
||||||
qDebug() << url;
|
qDebug() << "Opening url" << url;
|
||||||
if(url.host() == "gitea.nouspiro.space")
|
if(url.host() == "gitea.nouspiro.space")
|
||||||
QDesktopServices::openUrl(url);
|
QDesktopServices::openUrl(url);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user