Move source files to src directory
This commit is contained in:
@@ -0,0 +1,422 @@
|
||||
#include "databaseview.h"
|
||||
#include <QVBoxLayout>
|
||||
#include <QPushButton>
|
||||
#include <QSettings>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QHeaderView>
|
||||
#include <QSqlError>
|
||||
#include <QDebug>
|
||||
#include <QMenu>
|
||||
#include <QContextMenuEvent>
|
||||
#include <QRegularExpression>
|
||||
#include <iostream>
|
||||
#include "batchprocessing.h"
|
||||
|
||||
const QStringList DEFAULT_COLUMNS = {"EXPTIME", "OBJECT", "RA", "DEC"};
|
||||
|
||||
double RA(const QString &ra)
|
||||
{
|
||||
QRegularExpression reg("(\\d+)\\s*(\\d+)?\\s*(\\d+)?");
|
||||
QRegularExpressionMatch match = reg.match(ra);
|
||||
double h = match.captured(1).toDouble();
|
||||
double m = match.captured(2).toDouble();
|
||||
double s = match.captured(3).toDouble();
|
||||
qDebug() << "RA" << match.capturedTexts() << h << m << s;
|
||||
return h*15 + m*0.25 + s*15/3600;
|
||||
}
|
||||
|
||||
double DEC(const QString &dec)
|
||||
{
|
||||
QRegularExpression reg("([\\+\\-])?(\\d+)\\s*(\\d+)?\\s*(\\d+)?");
|
||||
QRegularExpressionMatch match = reg.match(dec);
|
||||
double sign = match.captured(1) == "-" ? -1 : 1;
|
||||
double d = match.captured(2).toDouble();
|
||||
double m = match.captured(3).toDouble();
|
||||
double s = match.captured(4).toDouble();
|
||||
qDebug() << "DEC" << match.capturedTexts() << sign << d << m << s;
|
||||
return sign * (d + m/60 + s/3600);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
FITSFileModel::FITSFileModel(Database *database, QObject *parent) : QSqlQueryModel(parent)
|
||||
, m_database(database)
|
||||
{
|
||||
}
|
||||
|
||||
void FITSFileModel::sort(int column, Qt::SortOrder order)
|
||||
{
|
||||
if(column < 0)
|
||||
m_sort.clear();
|
||||
else if(column <= m_columns.size())
|
||||
{
|
||||
if(column == 0)m_sort = " ORDER BY f.file ";
|
||||
else m_sort = QString(" ORDER BY \"h%1_value\" ").arg(column-1);
|
||||
m_sort += order == Qt::AscendingOrder ? "ASC" : "DESC";
|
||||
prepareQuery();
|
||||
}
|
||||
}
|
||||
|
||||
void FITSFileModel::setColumns(const QStringList &columns)
|
||||
{
|
||||
m_columns = columns;
|
||||
prepareQuery();
|
||||
}
|
||||
|
||||
void FITSFileModel::setFilter(const QStringList &key, const QStringList &value, const QStringList &limit)
|
||||
{
|
||||
if(value.isEmpty())
|
||||
{
|
||||
m_key.clear();
|
||||
m_value.clear();
|
||||
m_limit.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_key = key;
|
||||
m_value = value;
|
||||
m_limit = limit;
|
||||
}
|
||||
prepareQuery();
|
||||
}
|
||||
|
||||
QVariant FITSFileModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if(role == Qt::FontRole && index.column() == 0)
|
||||
{
|
||||
QFont font;
|
||||
QString file = index.data().toString();
|
||||
font.setBold(m_markedFiles.contains(file));
|
||||
return font;
|
||||
}
|
||||
if(role == Qt::ToolTipRole && index.column() == 0)
|
||||
{
|
||||
return QSqlQueryModel::data(index, Qt::DisplayRole);
|
||||
}
|
||||
return QSqlQueryModel::data(index, role);
|
||||
}
|
||||
|
||||
void FITSFileModel::filesMarked(const QModelIndexList &indexes)
|
||||
{
|
||||
for(auto &index : indexes)
|
||||
{
|
||||
QString file = index.data().toString();
|
||||
if(!m_markedFiles.contains(file))
|
||||
{
|
||||
m_markedFiles.insert(file);
|
||||
emit dataChanged(index, index, {Qt::FontRole});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FITSFileModel::filesUnmarked(const QModelIndexList &indexes)
|
||||
{
|
||||
for(auto &index : indexes)
|
||||
{
|
||||
QString file = index.data().toString();
|
||||
if(m_markedFiles.contains(file))
|
||||
{
|
||||
m_markedFiles.remove(file);
|
||||
emit dataChanged(index, index, {Qt::FontRole});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FITSFileModel::prepareQuery()
|
||||
{
|
||||
QString cols;
|
||||
QString join;
|
||||
QStringList where;
|
||||
QString sql = m_columns.size() ? "SELECT f.file," : "SELECT f.file";
|
||||
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]));
|
||||
else if(m_key[i] == "RA pos")
|
||||
where.append(QString(" %1 BETWEEN f.minRa AND f.maxRa ").arg(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])));
|
||||
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])));
|
||||
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])));
|
||||
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]);
|
||||
}
|
||||
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);
|
||||
i++;
|
||||
}
|
||||
cols.chop(1);
|
||||
sql += cols;
|
||||
sql += " FROM fits_files AS f";
|
||||
sql += join;
|
||||
if(!where.isEmpty())sql += " WHERE " + where.join("AND");
|
||||
sql += " GROUP BY f.id" + m_sort;
|
||||
setQuery(sql);
|
||||
setHeaderData(0, Qt::Horizontal, tr("File name"));
|
||||
i = 1;
|
||||
for(auto &column : m_columns)
|
||||
{
|
||||
setHeaderData(i++, Qt::Horizontal, column);
|
||||
}
|
||||
std::cout << sql.toStdString() << std::endl;
|
||||
if(lastError().type() != QSqlError::NoError)
|
||||
qDebug() << "Database error" << lastError();
|
||||
|
||||
QStringList list = m_database->getMarkedFiles();
|
||||
m_markedFiles = QSet<QString>(list.begin(), list.end());
|
||||
}
|
||||
|
||||
DatabaseTableView::DatabaseTableView(QWidget *parent) : QTableView(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void DatabaseTableView::contextMenuEvent(QContextMenuEvent *event)
|
||||
{
|
||||
QMenu menu;
|
||||
QAction *mark = menu.addAction(tr("Mark"));
|
||||
QAction *unmark = menu.addAction(tr("Unmark"));
|
||||
QAction *open = menu.addAction(tr("Open"));
|
||||
QAction *openDirAction = menu.addAction(tr("Open file location"));
|
||||
|
||||
QAction *a = menu.exec(event->globalPos());
|
||||
if(a == nullptr)
|
||||
return;
|
||||
|
||||
QModelIndexList indexes = selectionModel()->selectedRows();
|
||||
|
||||
if(a == mark)
|
||||
emit filesMarked(indexes);
|
||||
else if(a == unmark)
|
||||
emit filesUnmarked(indexes);
|
||||
else if(a == open)
|
||||
emit openFile(indexes);
|
||||
else if(a == openDirAction)
|
||||
emit openDir(indexes);
|
||||
}
|
||||
|
||||
DataBaseView::DataBaseView(Database *database, QWidget *parent) : QWidget(parent)
|
||||
,m_database(database)
|
||||
{
|
||||
QVBoxLayout *layout = new QVBoxLayout(this);
|
||||
setLayout(layout);
|
||||
|
||||
m_tableView = new DatabaseTableView(this);
|
||||
m_tableView->verticalHeader()->setDefaultSectionSize(1);
|
||||
m_tableView->setSortingEnabled(true);
|
||||
m_tableView->horizontalHeader()->setSortIndicatorShown(true);
|
||||
m_tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
layout->addWidget(m_tableView);
|
||||
connect(m_tableView, &QTableView::activated, this, &DataBaseView::itemActivated);
|
||||
|
||||
m_model = new FITSFileModel(m_database, this);
|
||||
|
||||
QSettings settings;
|
||||
m_tableView->setModel(m_model);
|
||||
m_model->setColumns(settings.value("databaseview/selectedColumns", DEFAULT_COLUMNS).toStringList());
|
||||
m_tableView->horizontalHeader()->restoreState(settings.value("databaseview/header").toByteArray());
|
||||
|
||||
QHBoxLayout *hlayout = new QHBoxLayout();
|
||||
layout->addLayout(hlayout);
|
||||
|
||||
QPushButton *selectColumnsButton = new QPushButton(tr("Select columns"), this);
|
||||
hlayout->addWidget(selectColumnsButton);
|
||||
connect(selectColumnsButton, &QPushButton::pressed, this, &DataBaseView::selectColumns);
|
||||
|
||||
connect(m_tableView, &DatabaseTableView::filesMarked, [this](QModelIndexList indexes){
|
||||
QStringList files;
|
||||
for(auto &index : indexes)
|
||||
files.append(index.data().toString());
|
||||
m_database->mark(files);
|
||||
m_model->filesMarked(indexes);
|
||||
});
|
||||
connect(m_tableView, &DatabaseTableView::filesUnmarked, [this](QModelIndexList indexes){
|
||||
QStringList files;
|
||||
for(auto &index : indexes)
|
||||
files.append(index.data().toString());
|
||||
m_database->unmark(files);
|
||||
m_model->filesUnmarked(indexes);
|
||||
});
|
||||
connect(m_tableView, &DatabaseTableView::openFile, [this](QModelIndexList indexes){
|
||||
if(indexes.size())
|
||||
emit loadFile(m_model->data(indexes.front().siblingAtColumn(0)).toString());
|
||||
});
|
||||
connect(m_tableView, &DatabaseTableView::openDir, [this](QModelIndexList indexes){
|
||||
if(indexes.size())
|
||||
{
|
||||
QFileInfo info(m_model->data(indexes.front().siblingAtColumn(0)).toString());
|
||||
openDir(info.absolutePath());
|
||||
}
|
||||
});
|
||||
|
||||
auto addFilterItems = [](QComboBox *combobox, const QStringList &fitsKeywords)
|
||||
{
|
||||
combobox->clear();
|
||||
combobox->addItem("file");
|
||||
combobox->addItem("RA pos");
|
||||
combobox->addItem("DEC pos");
|
||||
combobox->addItem("RA range");
|
||||
combobox->addItem("DEC range");
|
||||
combobox->addItems(fitsKeywords);
|
||||
};
|
||||
|
||||
QStringList fitsKeywords = m_database->getFitsKeywords();
|
||||
for(int i=0; i<3; i++)
|
||||
{
|
||||
m_filterKeyword[i] = new QComboBox(this);
|
||||
m_filterKeyword[i]->setMaximumWidth(300);
|
||||
addFilterItems(m_filterKeyword[i], fitsKeywords);
|
||||
|
||||
|
||||
m_search[i] = new QLineEdit(this);
|
||||
m_search[i]->setPlaceholderText(tr("Text to search, you can % as wildcard"));
|
||||
|
||||
m_limit[i] = new QLineEdit(this);
|
||||
m_limit[i]->hide();
|
||||
connect(m_filterKeyword[i], static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged), [this, i](int index){
|
||||
if(index == 3 || index == 4)m_limit[i]->show();
|
||||
else m_limit[i]->hide();
|
||||
});
|
||||
|
||||
connect(m_search[i], &QLineEdit::returnPressed, this, &DataBaseView::applyFilter);
|
||||
connect(m_limit[i], &QLineEdit::returnPressed, this, &DataBaseView::applyFilter);
|
||||
hlayout->addWidget(m_filterKeyword[i]);
|
||||
hlayout->addWidget(m_search[i]);
|
||||
hlayout->addWidget(m_limit[i]);
|
||||
}
|
||||
|
||||
QPushButton *filterButton = new QPushButton(tr("Filter"), this);
|
||||
connect(filterButton, &QPushButton::pressed, this, &DataBaseView::applyFilter);
|
||||
hlayout->addWidget(filterButton);
|
||||
|
||||
connect(m_database, &Database::databaseChanged, [this, &addFilterItems](){
|
||||
QStringList fitsKeywords = m_database->getFitsKeywords();
|
||||
for(int i=0; i<3; i++)
|
||||
addFilterItems(m_filterKeyword[i], fitsKeywords);
|
||||
|
||||
applyFilter();
|
||||
});
|
||||
}
|
||||
|
||||
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);
|
||||
m_model->setColumns(columns);
|
||||
}
|
||||
}
|
||||
|
||||
void DataBaseView::loadDatabase()
|
||||
{
|
||||
QSettings settings;
|
||||
m_model->setColumns(settings.value("databaseview/selectedColumns", DEFAULT_COLUMNS).toStringList());
|
||||
}
|
||||
|
||||
void DataBaseView::itemActivated(const QModelIndex &index)
|
||||
{
|
||||
emit loadFile(m_model->data(index.siblingAtColumn(0)).toString());
|
||||
}
|
||||
|
||||
void DataBaseView::applyFilter()
|
||||
{
|
||||
QStringList keys;
|
||||
QStringList values;
|
||||
QStringList limits;
|
||||
for(int i=0; i<3; i++)
|
||||
{
|
||||
QString key = m_filterKeyword[i]->currentText();
|
||||
if(!m_search[i]->text().isEmpty() && !keys.contains(key))
|
||||
{
|
||||
keys.append(key);
|
||||
values.append(m_search[i]->text());
|
||||
limits.append(m_limit[i]->text());
|
||||
}
|
||||
}
|
||||
m_model->setFilter(keys, values, limits);
|
||||
}
|
||||
|
||||
bool DataBaseView::exportCSV(const QString &path)
|
||||
{
|
||||
QFile csv(path);
|
||||
if(!csv.open(QIODevice::WriteOnly | QIODevice::Text))
|
||||
return false;
|
||||
|
||||
QSqlQuery sql(m_model->query().lastQuery());
|
||||
int colCount = m_model->columnCount();
|
||||
QStringList header;
|
||||
for(int i=0; i<colCount; i++)
|
||||
header.append(m_model->headerData(i, Qt::Horizontal).toString());
|
||||
|
||||
csv.write(header.join(",").toUtf8());
|
||||
csv.write("\n");
|
||||
|
||||
while(sql.next())
|
||||
{
|
||||
QStringList columns;
|
||||
for(int i=0; i<colCount; i++)
|
||||
{
|
||||
QString val = sql.value(i).toString();
|
||||
val.replace("\"", "\"\"");
|
||||
if(val.contains('"') || val.contains(','))
|
||||
{
|
||||
val.prepend('"');
|
||||
val.append('"');
|
||||
}
|
||||
columns.append(val);
|
||||
}
|
||||
csv.write(columns.join(",").toUtf8());
|
||||
csv.write("\n");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
Reference in New Issue
Block a user