File indexing completed on 2024-05-12 15:28:19
0001 /*************************************************************************** 0002 File : FITSHeaderEditWidget.cpp 0003 Project : LabPlot 0004 Description : Widget for listing/editing FITS header keywords 0005 -------------------------------------------------------------------- 0006 Copyright : (C) 2016-2017 by Fabian Kristof (fkristofszabolcs@gmail.com) 0007 ***************************************************************************/ 0008 0009 /*************************************************************************** 0010 * * 0011 * This program is free software; you can redistribute it and/or modify * 0012 * it under the terms of the GNU General Public License as published by * 0013 * the Free Software Foundation; either version 2 of the License, or * 0014 * (at your option) any later version. * 0015 * * 0016 * This program is distributed in the hope that it will be useful, * 0017 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0019 * GNU General Public License for more details. * 0020 * * 0021 * You should have received a copy of the GNU General Public License * 0022 * along with this program; if not, write to the Free Software * 0023 * Foundation, Inc., 51 Franklin Street, Fifth Floor, * 0024 * Boston, MA 02110-1301 USA * 0025 * * 0026 ***************************************************************************/ 0027 0028 #include "FITSHeaderEditWidget.h" 0029 #include "ui_fitsheadereditwidget.h" 0030 #include "backend/datasources/filters/FITSFilter.h" 0031 #include "backend/lib/macros.h" 0032 #include "FITSHeaderEditNewKeywordDialog.h" 0033 #include "FITSHeaderEditAddUnitDialog.h" 0034 0035 #include <QMenu> 0036 #include <QTableWidget> 0037 #include <QFileDialog> 0038 #include <QContextMenuEvent> 0039 #include <QPushButton> 0040 #include <KConfigGroup> 0041 #include <KMessageBox> 0042 #include <KSharedConfig> 0043 0044 /*! \class FITSHeaderEditWidget 0045 * \brief Widget for listing/editing FITS header keywords 0046 * \since 2.4.0 0047 * \ingroup kdefrontend/widgets 0048 */ 0049 FITSHeaderEditWidget::FITSHeaderEditWidget(QWidget* parent) : QWidget(parent), 0050 ui(new Ui::FITSHeaderEditWidget()), 0051 m_fitsFilter(new FITSFilter()) { 0052 0053 ui->setupUi(this); 0054 initActions(); 0055 connectActions(); 0056 initContextMenus(); 0057 0058 ui->bOpen->setIcon(QIcon::fromTheme("document-open")); 0059 0060 ui->bAddKey->setIcon(QIcon::fromTheme("list-add")); 0061 ui->bAddKey->setEnabled(false); 0062 ui->bAddKey->setToolTip(i18n("Add new keyword")); 0063 0064 ui->bRemoveKey->setIcon(QIcon::fromTheme("list-remove")); 0065 ui->bRemoveKey->setEnabled(false); 0066 ui->bRemoveKey->setToolTip(i18n("Remove selected keyword")); 0067 0068 ui->bAddUnit->setIcon(QIcon::fromTheme("document-new")); 0069 ui->bAddUnit->setEnabled(false); 0070 ui->bAddUnit->setToolTip(i18n("Add unit to keyword")); 0071 0072 ui->bClose->setIcon(QIcon::fromTheme("document-close")); 0073 ui->bClose->setEnabled(false); 0074 ui->bClose->setToolTip(i18n("Close file")); 0075 0076 ui->twKeywordsTable->setColumnCount(3); 0077 ui->twExtensions->setSelectionMode(QAbstractItemView::SingleSelection); 0078 ui->twExtensions->headerItem()->setText(0, i18n("Content")); 0079 ui->twKeywordsTable->setHorizontalHeaderItem(0, new QTableWidgetItem(i18n("Key"))); 0080 ui->twKeywordsTable->setHorizontalHeaderItem(1, new QTableWidgetItem(i18n("Value"))); 0081 ui->twKeywordsTable->setHorizontalHeaderItem(2, new QTableWidgetItem(i18n("Comment"))); 0082 ui->twKeywordsTable->setAlternatingRowColors(true); 0083 ui->twKeywordsTable->horizontalHeader()->resizeSections(QHeaderView::ResizeToContents); 0084 ui->twKeywordsTable->horizontalHeader()->setStretchLastSection(true); 0085 ui->twKeywordsTable->installEventFilter(this); 0086 ui->twExtensions->installEventFilter(this); 0087 0088 setAttribute(Qt::WA_DeleteOnClose); 0089 0090 connect(ui->bAddUnit, &QPushButton::clicked, m_actionAddmodifyUnit, &QAction::triggered); 0091 connect(ui->bClose, &QPushButton::clicked, this, &FITSHeaderEditWidget::closeFile); 0092 connect(ui->bOpen, &QPushButton::clicked, this, &FITSHeaderEditWidget::openFile); 0093 connect(ui->bAddKey, &QPushButton::clicked, this, &FITSHeaderEditWidget::addKeyword); 0094 connect(ui->bRemoveKey, &QPushButton::clicked, this, &FITSHeaderEditWidget::removeKeyword); 0095 connect(ui->twKeywordsTable, &QTableWidget::itemClicked, this, &FITSHeaderEditWidget::enableButtonAddUnit); 0096 connect(ui->twKeywordsTable, &QTableWidget::itemChanged, this, &FITSHeaderEditWidget::updateKeyword); 0097 connect(ui->twExtensions, &QTreeWidget::itemClicked, this, &FITSHeaderEditWidget::fillTableSlot); 0098 connect(ui->twExtensions, &QTreeWidget::itemClicked, this, &FITSHeaderEditWidget::enableButtonCloseFile); 0099 } 0100 0101 /*! 0102 * \brief Destructor 0103 */ 0104 FITSHeaderEditWidget::~FITSHeaderEditWidget() { 0105 delete m_fitsFilter; 0106 } 0107 0108 /*! 0109 * \brief Fills the keywords tablewidget. 0110 * If the selected extension was not yet selected before, then the keywords are read from the file 0111 * and then the table is filled, otherwise the table is filled using the already existing keywords. 0112 */ 0113 void FITSHeaderEditWidget::fillTable() { 0114 m_initializingTable = true; 0115 if (!m_extensionData.contains(m_seletedExtension)) { 0116 m_extensionData[m_seletedExtension].keywords = m_fitsFilter->chduKeywords(m_seletedExtension); 0117 m_extensionData[m_seletedExtension].updates.updatedKeywords.reserve(m_extensionData[m_seletedExtension].keywords.size()); 0118 m_extensionData[m_seletedExtension].updates.updatedKeywords.resize(m_extensionData[m_seletedExtension].keywords.size()); 0119 0120 m_fitsFilter->parseHeader(m_seletedExtension, ui->twKeywordsTable); 0121 } else { 0122 QList<FITSFilter::Keyword> keywords = m_extensionData[m_seletedExtension].keywords; 0123 for (int i = 0; i < m_extensionData[m_seletedExtension].updates.updatedKeywords.size(); ++i) { 0124 FITSFilter::Keyword keyword = m_extensionData[m_seletedExtension].updates.updatedKeywords.at(i); 0125 if (!keyword.key.isEmpty()) 0126 keywords.operator [](i).key = keyword.key; 0127 if (!keyword.value.isEmpty()) 0128 keywords.operator [](i).value = keyword.value; 0129 if (!keyword.comment.isEmpty()) 0130 keywords.operator [](i).comment = keyword.comment; 0131 } 0132 for (const FITSFilter::Keyword& key : m_extensionData[m_seletedExtension].updates.newKeywords) 0133 keywords.append(key); 0134 m_fitsFilter->parseHeader(QString(), ui->twKeywordsTable, false, keywords); 0135 } 0136 m_initializingTable = false; 0137 } 0138 0139 /*! 0140 * \brief Fills the tablewidget with the keywords of extension \a item 0141 * \param item the extension selected 0142 * \param col the column of the selected item 0143 */ 0144 void FITSHeaderEditWidget::fillTableSlot(QTreeWidgetItem *item, int col) { 0145 WAIT_CURSOR; 0146 const QString& itemText = item->text(col); 0147 QString selectedExtension; 0148 int extType = 0; 0149 if (itemText.contains(QLatin1String("IMAGE #")) || 0150 itemText.contains(QLatin1String("ASCII_TBL #")) || 0151 itemText.contains(QLatin1String("BINARY_TBL #"))) 0152 extType = 1; 0153 else if (!itemText.compare(QLatin1String("Primary header"))) 0154 extType = 2; 0155 if (extType == 0) { 0156 if (item->parent() != nullptr) { 0157 if (item->parent()->parent() != nullptr) 0158 selectedExtension = item->parent()->parent()->text(0) + '[' + item->text(col) + ']'; 0159 } 0160 } else if (extType == 1) { 0161 if (item->parent() != nullptr) { 0162 if (item->parent()->parent() != nullptr) { 0163 bool ok; 0164 int hduNum = itemText.rightRef(1).toInt(&ok); 0165 selectedExtension = item->parent()->parent()->text(0) + '[' + QString::number(hduNum-1) + ']'; 0166 } 0167 } 0168 } else { 0169 if (item->parent()->parent() != nullptr) 0170 selectedExtension = item->parent()->parent()->text(col); 0171 } 0172 0173 if (!selectedExtension.isEmpty()) { 0174 if (!(m_seletedExtension == selectedExtension)) { 0175 m_seletedExtension = selectedExtension; 0176 fillTable(); 0177 } 0178 } 0179 RESET_CURSOR; 0180 } 0181 0182 /*! 0183 * \brief Shows a dialog for opening a FITS file 0184 * If the returned file name is not empty (so a FITS file was selected) and it's not opened yet 0185 * then the file is parsed, so the treeview for the extensions is built and the table is filled. 0186 */ 0187 void FITSHeaderEditWidget::openFile() { 0188 KConfigGroup conf(KSharedConfig::openConfig(), "FITSHeaderEditWidget"); 0189 QString dir = conf.readEntry("LastDir", ""); 0190 QString fileName = QFileDialog::getOpenFileName(this, i18n("Open FITS file"), dir, 0191 i18n("FITS files (*.fits *.fit *.fts)")); 0192 if (fileName.isEmpty()) 0193 return; 0194 0195 int pos = fileName.lastIndexOf(QLatin1String("/")); 0196 if (pos != -1) { 0197 QString newDir = fileName.left(pos); 0198 if (newDir != dir) 0199 conf.writeEntry("LastDir", newDir); 0200 } 0201 0202 WAIT_CURSOR; 0203 QTreeWidgetItem* root = ui->twExtensions->invisibleRootItem(); 0204 const int childCount = root->childCount(); 0205 bool opened = false; 0206 for (int i = 0; i < childCount; ++i) { 0207 if (root->child(i)->text(0) == fileName) { 0208 opened = true; 0209 break; 0210 } 0211 } 0212 if (!opened) { 0213 for (QTreeWidgetItem* item : ui->twExtensions->selectedItems()) 0214 item->setSelected(false); 0215 m_fitsFilter->parseExtensions(fileName, ui->twExtensions); 0216 ui->twExtensions->resizeColumnToContents(0); 0217 if (ui->twExtensions->selectedItems().size() > 0) 0218 fillTableSlot(ui->twExtensions->selectedItems().at(0), 0); 0219 0220 ui->bAddKey->setEnabled(true); 0221 ui->bRemoveKey->setEnabled(true); 0222 ui->bAddUnit->setEnabled(true); 0223 ui->bClose->setEnabled(false); 0224 0225 } else { 0226 KMessageBox::information(this, i18n("Cannot open file, file already opened."), 0227 i18n("File already opened")); 0228 } 0229 enableButtonAddUnit(); 0230 RESET_CURSOR; 0231 } 0232 0233 /*! 0234 * \brief Triggered when clicking the Save button 0235 * Saves the modifications (new keywords, new keyword units, keyword modifications, 0236 * deleted keywords, deleted extensions) to the FITS files. 0237 * \return \c true if there was something saved, otherwise false 0238 */ 0239 bool FITSHeaderEditWidget::save() { 0240 bool saved = false; 0241 0242 QMap<QString, ExtensionData>::const_iterator it = m_extensionData.constBegin(); 0243 while (it != m_extensionData.constEnd()) { 0244 const QString& fileName = it.key(); 0245 const auto& data = it.value(); 0246 if (data.updates.newKeywords.size() > 0) { 0247 m_fitsFilter->addNewKeyword(fileName, data.updates.newKeywords); 0248 if (!saved) 0249 saved = true; 0250 } 0251 if (data.updates.removedKeywords.size() > 0) { 0252 m_fitsFilter->deleteKeyword(fileName, data.updates.removedKeywords); 0253 if (!saved) 0254 saved = true; 0255 } 0256 if (!saved) { 0257 for (const FITSFilter::Keyword& key : data.updates.updatedKeywords) { 0258 if (!key.isEmpty()) { 0259 saved = true; 0260 break; 0261 } 0262 } 0263 } 0264 0265 m_fitsFilter->updateKeywords(fileName, data.keywords, data.updates.updatedKeywords); 0266 m_fitsFilter->addKeywordUnit(fileName, data.keywords); 0267 m_fitsFilter->addKeywordUnit(fileName, data.updates.newKeywords); 0268 0269 ++it; 0270 } 0271 0272 if (m_removedExtensions.size() > 0) { 0273 m_fitsFilter->removeExtensions(m_removedExtensions); 0274 if (!saved) 0275 saved = true; 0276 } 0277 if (saved) { 0278 //to reset the window title 0279 emit changed(false); 0280 } 0281 0282 return saved; 0283 } 0284 0285 /*! 0286 * \brief Initializes the context menu's actions. 0287 */ 0288 void FITSHeaderEditWidget::initActions() { 0289 m_actionAddKeyword = new QAction(QIcon::fromTheme("list-add"), i18n("Add New Keyword"), this); 0290 m_actionRemoveKeyword = new QAction(QIcon::fromTheme("list-remove"), i18n("Remove Keyword"), this); 0291 m_actionRemoveExtension = new QAction(i18n("Delete"), this); 0292 m_actionAddmodifyUnit = new QAction(i18n("Add Unit"), this); 0293 } 0294 0295 /*! 0296 * \brief Connects signals of the actions to the appropriate slots. 0297 */ 0298 void FITSHeaderEditWidget::connectActions() { 0299 connect(m_actionAddKeyword, &QAction::triggered, this, [=](){addKeyword();}); 0300 connect(m_actionRemoveKeyword, &QAction::triggered, this, [=](){removeKeyword();}); 0301 connect(m_actionRemoveExtension, &QAction::triggered, this, [=](){removeExtension();}); 0302 connect(m_actionAddmodifyUnit, &QAction::triggered, this, [=](){addModifyKeywordUnit();}); 0303 } 0304 0305 /*! 0306 * \brief Initializes the context menus. 0307 */ 0308 void FITSHeaderEditWidget::initContextMenus() { 0309 m_keywordActionsMenu = new QMenu(this); 0310 m_keywordActionsMenu->addAction(m_actionAddKeyword); 0311 m_keywordActionsMenu->addAction(m_actionRemoveKeyword); 0312 m_keywordActionsMenu->addSeparator(); 0313 m_keywordActionsMenu->addAction(m_actionAddmodifyUnit); 0314 0315 m_extensionActionsMenu = new QMenu(this); 0316 m_extensionActionsMenu->addAction(m_actionRemoveExtension); 0317 } 0318 0319 /*! 0320 * \brief Shows a FITSHeaderEditNewKeywordDialog and decides whether the new keyword provided in the dialog 0321 * can be added to the new keywords or not. Updates the tablewidget if it's needed. 0322 */ 0323 void FITSHeaderEditWidget::addKeyword() { 0324 auto* newKeywordDialog = new FITSHeaderEditNewKeywordDialog; 0325 m_initializingTable = true; 0326 if (newKeywordDialog->exec() == QDialog::Accepted) { 0327 FITSFilter::Keyword newKeyWord = newKeywordDialog->newKeyword(); 0328 QList<FITSFilter::Keyword> currentKeywords = m_extensionData[m_seletedExtension].keywords; 0329 0330 for (const FITSFilter::Keyword& keyword : currentKeywords) { 0331 if (keyword.operator == (newKeyWord)) { 0332 KMessageBox::information(this, i18n("Cannot add keyword, keyword already added"), i18n("Cannot Add Keyword")); 0333 return; 0334 } 0335 } 0336 0337 for (const FITSFilter::Keyword& keyword : m_extensionData[m_seletedExtension].updates.newKeywords) { 0338 if (keyword.operator == (newKeyWord)) { 0339 KMessageBox::information(this, i18n("Cannot add keyword, keyword already added"), i18n("Cannot Add Keyword")); 0340 return; 0341 } 0342 } 0343 0344 for (const QString& keyword : mandatoryKeywords()) { 0345 if (!keyword.compare(newKeyWord.key)) { 0346 KMessageBox::information(this, i18n("Cannot add mandatory keyword, they are already present"), 0347 i18n("Cannot Add Keyword")); 0348 return; 0349 } 0350 } 0351 0352 /* 0353 - Column related keyword (TFIELDS, TTYPEn,TFORMn, etc.) in an image 0354 - SIMPLE, EXTEND, or BLOCKED keyword in any extension 0355 - BSCALE, BZERO, BUNIT, BLANK, DATAMAX, DATAMIN keywords in a table 0356 - Keyword name contains illegal character 0357 */ 0358 0359 m_extensionData[m_seletedExtension].updates.newKeywords.append(newKeyWord); 0360 0361 const int lastRow = ui->twKeywordsTable->rowCount(); 0362 ui->twKeywordsTable->setRowCount(lastRow + 1); 0363 auto* newKeyWordItem = new QTableWidgetItem(newKeyWord.key); 0364 newKeyWordItem->setFlags(Qt::ItemIsEditable | Qt::ItemIsSelectable | Qt::ItemIsEnabled); 0365 ui->twKeywordsTable->setItem(lastRow, 0, newKeyWordItem); 0366 0367 newKeyWordItem = new QTableWidgetItem(newKeyWord.value); 0368 newKeyWordItem->setFlags(Qt::ItemIsEditable | Qt::ItemIsSelectable | Qt::ItemIsEnabled); 0369 ui->twKeywordsTable->setItem(lastRow, 1, newKeyWordItem); 0370 0371 newKeyWordItem = new QTableWidgetItem(newKeyWord.comment); 0372 newKeyWordItem->setFlags(Qt::ItemIsEditable | Qt::ItemIsSelectable | Qt::ItemIsEnabled); 0373 ui->twKeywordsTable->setItem(lastRow, 2, newKeyWordItem); 0374 emit changed(true); 0375 } 0376 m_initializingTable = false; 0377 delete newKeywordDialog; 0378 } 0379 0380 /*! 0381 * \brief Shows a messagebox whether we want to remove the keyword or not. 0382 * Mandatory keywords cannot be deleted. 0383 */ 0384 void FITSHeaderEditWidget::removeKeyword() { 0385 const int row = ui->twKeywordsTable->currentRow(); 0386 if (row == -1) 0387 return; 0388 0389 QString key = ui->twKeywordsTable->item(row, 0)->text(); 0390 const int rc = KMessageBox::questionYesNo(this, i18n("Are you sure you want to delete the keyword '%1'?", key), 0391 i18n("Confirm Deletion")); 0392 if (rc == KMessageBox::Yes) { 0393 bool remove = true; 0394 for (const QString& k : mandatoryKeywords()) { 0395 if (!k.compare(key)) { 0396 remove = false; 0397 break; 0398 } 0399 } 0400 0401 if (remove) { 0402 FITSFilter::Keyword toRemove = FITSFilter::Keyword(key, 0403 ui->twKeywordsTable->item(row, 1)->text(), 0404 ui->twKeywordsTable->item(row, 2)->text()); 0405 ui->twKeywordsTable->removeRow(row); 0406 0407 m_extensionData[m_seletedExtension].keywords.removeAt(row); 0408 m_extensionData[m_seletedExtension].updates.removedKeywords.append(toRemove); 0409 emit changed(true); 0410 } else 0411 KMessageBox::information(this, i18n("Cannot remove mandatory keyword."), i18n("Removing Keyword")); 0412 } 0413 0414 enableButtonAddUnit(); 0415 } 0416 0417 /*! 0418 * \brief Trigggered when an item was updated by the user in the tablewidget 0419 * \param item the item which was updated 0420 */ 0421 void FITSHeaderEditWidget::updateKeyword(QTableWidgetItem *item) { 0422 if (!m_initializingTable) { 0423 const int row = item->row(); 0424 if (row < 0) 0425 return; 0426 0427 int idx; 0428 bool fromNewKeyword = false; 0429 if (row > m_extensionData[m_seletedExtension].keywords.size()-1) { 0430 idx = row - m_extensionData[m_seletedExtension].keywords.size(); 0431 fromNewKeyword = true; 0432 } else 0433 idx = row; 0434 0435 if (item->column() == 0) { 0436 if (!fromNewKeyword) { 0437 m_extensionData[m_seletedExtension].updates.updatedKeywords.operator [](idx).key = item->text(); 0438 m_extensionData[m_seletedExtension].keywords.operator [](idx).updates.keyUpdated = true; 0439 } else { 0440 m_extensionData[m_seletedExtension].updates.newKeywords.operator [](idx).key = item->text(); 0441 m_extensionData[m_seletedExtension].updates.newKeywords.operator [](idx).updates.keyUpdated = true; 0442 } 0443 0444 } else if (item->column() == 1) { 0445 if (!fromNewKeyword) { 0446 m_extensionData[m_seletedExtension].updates.updatedKeywords.operator [](idx).value = item->text(); 0447 m_extensionData[m_seletedExtension].keywords.operator [](idx).updates.valueUpdated = true; 0448 } else { 0449 m_extensionData[m_seletedExtension].updates.newKeywords.operator [](idx).value = item->text(); 0450 m_extensionData[m_seletedExtension].updates.newKeywords.operator [](idx).updates.valueUpdated = true; 0451 } 0452 } else { 0453 if (!fromNewKeyword) { 0454 m_extensionData[m_seletedExtension].updates.updatedKeywords.operator [](idx).comment = item->text(); 0455 m_extensionData[m_seletedExtension].keywords.operator [](idx).updates.commentUpdated = true; 0456 } else { 0457 m_extensionData[m_seletedExtension].updates.newKeywords.operator [](idx).comment = item->text(); 0458 m_extensionData[m_seletedExtension].updates.newKeywords.operator [](idx).updates.commentUpdated = true; 0459 } 0460 } 0461 emit changed(true); 0462 } 0463 } 0464 0465 /*! 0466 * \brief Shows a FITSHeaderEditAddUnitDialog on the selected keyword (provides the keyword's unit to the 0467 * dialog if it had one) and if the dialog was accepted then the new keyword unit is set and the tablewidget 0468 * is updated (filled with the modifications). 0469 */ 0470 0471 void FITSHeaderEditWidget::addModifyKeywordUnit() { 0472 FITSHeaderEditAddUnitDialog* addUnitDialog; 0473 0474 const int selectedRow = ui->twKeywordsTable->currentRow(); 0475 int idx; 0476 bool fromNewKeyword = false; 0477 if (selectedRow > m_extensionData[m_seletedExtension].keywords.size()-1) { 0478 idx = selectedRow - m_extensionData[m_seletedExtension].keywords.size(); 0479 fromNewKeyword = true; 0480 } else 0481 idx = selectedRow; 0482 0483 QString unit; 0484 if (fromNewKeyword) { 0485 if (!m_extensionData[m_seletedExtension].updates.newKeywords.at(idx).unit.isEmpty()) 0486 unit = m_extensionData[m_seletedExtension].updates.newKeywords.at(idx).unit; 0487 } else { 0488 if (!m_extensionData[m_seletedExtension].keywords.at(idx).unit.isEmpty()) 0489 unit = m_extensionData[m_seletedExtension].keywords.at(idx).unit; 0490 } 0491 0492 addUnitDialog = new FITSHeaderEditAddUnitDialog(unit); 0493 if (addUnitDialog->exec() == QDialog::Accepted) { 0494 if (fromNewKeyword) { 0495 m_extensionData[m_seletedExtension].updates.newKeywords.operator [](idx).unit = addUnitDialog->unit(); 0496 if (!m_extensionData[m_seletedExtension].updates.newKeywords.at(idx).unit.isEmpty()) { 0497 m_extensionData[m_seletedExtension].updates.newKeywords.operator [](idx).updates.unitUpdated = true; 0498 } 0499 } else { 0500 m_extensionData[m_seletedExtension].keywords.operator [](idx).unit = addUnitDialog->unit(); 0501 if (!m_extensionData[m_seletedExtension].keywords.at(idx).unit.isEmpty()) 0502 m_extensionData[m_seletedExtension].keywords.operator [](idx).updates.unitUpdated = true; 0503 } 0504 emit changed(true); 0505 fillTable(); 0506 } 0507 0508 delete addUnitDialog; 0509 } 0510 0511 /*! 0512 * \brief Removes the selected extension from the extensions treeview 0513 * If the last extension is removed from the tree, then the extension and the file will be removed too. 0514 */ 0515 void FITSHeaderEditWidget::removeExtension() { 0516 QTreeWidgetItem* current = ui->twExtensions->currentItem(); 0517 QTreeWidgetItem* newCurrent = ui->twExtensions->itemBelow(current); 0518 if (current->parent()) { 0519 if (current->parent()->childCount() < 2) 0520 delete current->parent(); 0521 else 0522 delete current; 0523 } 0524 const QStringList keys = m_extensionData.keys(); 0525 const int selectedidx = keys.indexOf(m_seletedExtension); 0526 0527 if (selectedidx > 0) { 0528 const QString& ext = m_seletedExtension; 0529 m_extensionData.remove(ext); 0530 m_removedExtensions.append(ext); 0531 m_seletedExtension = keys.at(selectedidx-1); 0532 0533 fillTable(); 0534 } 0535 ui->twExtensions->setCurrentItem(newCurrent); 0536 emit changed(true); 0537 } 0538 0539 /*! 0540 * \brief Returns a list of mandatory keywords according to the currently selected extension. 0541 * If the currently selected extension is an image then it returns the mandatory keywords of an image, 0542 * otherwise the mandatory keywords of a table 0543 * \return a list of mandatory keywords 0544 */ 0545 QList<QString> FITSHeaderEditWidget::mandatoryKeywords() const { 0546 QList<QString> mandatoryKeywords; 0547 const QTreeWidgetItem* currentItem = ui->twExtensions->currentItem(); 0548 if (currentItem->parent()->text(0).compare(QLatin1String("Images"))) 0549 mandatoryKeywords = FITSFilter::mandatoryImageExtensionKeywords(); 0550 else 0551 mandatoryKeywords = FITSFilter::mandatoryTableExtensionKeywords(); 0552 return mandatoryKeywords; 0553 } 0554 0555 /*! 0556 * \brief Manipulates the contextmenu event of the widget 0557 * \param watched the object on which the event occurred 0558 * \param event the event watched 0559 * \return 0560 */ 0561 bool FITSHeaderEditWidget::eventFilter(QObject* watched, QEvent* event) { 0562 if (event->type() == QEvent::ContextMenu) { 0563 auto* cm_event = static_cast<QContextMenuEvent*>(event); 0564 const QPoint& global_pos = cm_event->globalPos(); 0565 if (watched == ui->twKeywordsTable) { 0566 if (ui->twExtensions->selectedItems().size() != 0) 0567 m_keywordActionsMenu->exec(global_pos); 0568 } else if (watched == ui->twExtensions) { 0569 if (ui->twExtensions->selectedItems().size() != 0) { 0570 QTreeWidgetItem* current = ui->twExtensions->currentItem(); 0571 int col = ui->twExtensions->currentColumn(); 0572 if (current->parent()) { 0573 if ((current->text(col) != QLatin1String("Images")) && 0574 (current->text(col) != QLatin1String("Tables"))) 0575 m_extensionActionsMenu->exec(global_pos); 0576 } 0577 } 0578 } else 0579 return QWidget::eventFilter(watched, event); 0580 return true; 0581 } else 0582 return QWidget::eventFilter(watched, event); 0583 } 0584 0585 void FITSHeaderEditWidget::closeFile() { 0586 if (ui->twExtensions->currentItem()) { 0587 QTreeWidgetItem* current = ui->twExtensions->currentItem(); 0588 0589 int idxOfCurrentAsTopLevel = -1; 0590 for (int i = 0; i < ui->twExtensions->topLevelItemCount(); ++i) { 0591 if (current == ui->twExtensions->topLevelItem(i)) { 0592 idxOfCurrentAsTopLevel = i; 0593 break; 0594 } 0595 } 0596 0597 auto* newCurrent = (QTreeWidgetItem*)nullptr; 0598 if (idxOfCurrentAsTopLevel == 0) { 0599 if (ui->twExtensions->topLevelItemCount() == 1) { 0600 //last file closed, deactivate action buttons, clear keywords table 0601 ui->twKeywordsTable->setRowCount(0); 0602 ui->bClose->setEnabled(false); 0603 ui->bAddUnit->setEnabled(false); 0604 ui->bAddKey->setEnabled(false); 0605 ui->bRemoveKey->setEnabled(false); 0606 } else 0607 newCurrent = ui->twExtensions->topLevelItem(idxOfCurrentAsTopLevel + 1); 0608 } else 0609 newCurrent = ui->twExtensions->topLevelItem(idxOfCurrentAsTopLevel - 1); 0610 0611 if (newCurrent) { 0612 m_seletedExtension = newCurrent->text(0); 0613 fillTable(); 0614 } 0615 QMap<QString, ExtensionData>::const_iterator it = m_extensionData.constBegin(); 0616 while (it != m_extensionData.constEnd()) { 0617 const QString& key = it.key(); 0618 if (key.startsWith(current->text(0))) 0619 m_extensionData.remove(key); 0620 ++it; 0621 } 0622 0623 delete current; 0624 0625 enableButtonAddUnit(); 0626 emit changed(false); 0627 } 0628 } 0629 void FITSHeaderEditWidget::enableButtonAddUnit() { 0630 if (ui->twKeywordsTable->currentItem() != nullptr) 0631 ui->bAddUnit->setEnabled(true); 0632 else 0633 ui->bAddUnit->setEnabled(false); 0634 } 0635 0636 void FITSHeaderEditWidget::enableButtonCloseFile(QTreeWidgetItem* item,int col) { 0637 Q_UNUSED(col) 0638 ui->bClose->setEnabled(item->parent() ? false : true); 0639 }