#include "databaseview.h" #include #include #include #include #include #include #include #include #include #include #include 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; igetMarkedFiles(); m_markedFiles = QSet(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 *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); } 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); }); 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(&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, SIGNAL(pressed()), this, SLOT(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(); int colCount = m_model->columnCount(); QStringList header; for(int i=0; iheaderData(i, Qt::Horizontal).toString()); csv.write(header.join(",").toUtf8()); csv.write("\n"); while(sql.next()) { QStringList columns; for(int i=0; i