Loading isis/src/qisis/objs/JigsawSetupDialog/JigsawSetupDialog.cpp +423 −53 Original line number Diff line number Diff line Loading @@ -10,10 +10,13 @@ #include <QStandardItemModel> #include <QItemSelection> #include "BundleObservationSolveSettings.h" #include "BundleSolutionInfo.h" #include "BundleSettings.h" #include "BundleTargetBody.h" #include "Control.h" #include "Cube.h" #include "Image.h" #include "IString.h" #include "MaximumLikelihoodWFunctions.h" #include "Project.h" Loading Loading @@ -98,20 +101,40 @@ namespace Isis { // Update setup dialog with settings from any active (current) settings in jigsaw dialog. // initializations for observation solve settings tab createObservationSolveSettingsTreeView(); m_ui->spkSolveDegreeSpinBox->setValue(-1); // Populate the solve option comboboxes const QStringList positionOptions{"NONE", "POSITION", "VELOCITY", "ACCELERATION", "ALL"}; m_ui->positionComboBox->insertItems(0, positionOptions); m_ui->positionComboBox->setCurrentIndex(0); const QStringList pointingOptions{"NONE", "ANGLES", "VELOCITY", "ACCELERATION", "ALL"}; m_ui->pointingComboBox->insertItems(0, pointingOptions); m_ui->pointingComboBox->setCurrentIndex(0); // The degree solve options' minimums are -1 (set in ui file), make the -1's display as N/A m_ui->spkSolveDegreeSpinBox->setSpecialValueText("N/A"); m_ui->ckSolveDegreeSpinBox->setSpecialValueText("N/A"); QStringList tableHeaders; tableHeaders << "coefficients" << "a priori sigma" << "units"; tableHeaders << "coefficients" << "description" << "units" << "a priori sigma"; m_ui->positionAprioriSigmaTable->setHorizontalHeaderLabels(tableHeaders); m_ui->positionAprioriSigmaTable->setColumnWidth(0, fontMetrics().width(tableHeaders.at(0))); m_ui->positionAprioriSigmaTable->setColumnWidth(1, fontMetrics().width(tableHeaders.at(1))); m_ui->positionAprioriSigmaTable->setColumnWidth(2, fontMetrics().width(tableHeaders.at(2))); m_ui->positionAprioriSigmaTable->setColumnWidth(0, fontMetrics().width(tableHeaders.at(0)) + 10); m_ui->positionAprioriSigmaTable->setColumnWidth(1, fontMetrics().width(tableHeaders.at(1)) + 10); m_ui->positionAprioriSigmaTable->setColumnWidth(2, fontMetrics().width(tableHeaders.at(2)) + 10); m_ui->positionAprioriSigmaTable->setColumnWidth(3, fontMetrics().width(tableHeaders.at(3)) + 10); m_ui->pointingAprioriSigmaTable->setHorizontalHeaderLabels(tableHeaders); // Add validators to the tables in the observation solve settings tab to validate the a priori // sigma items connect(m_ui->positionAprioriSigmaTable, SIGNAL(itemChanged(QTableWidgetItem *)), this, SLOT(validateSigmaValue(QTableWidgetItem *))); connect(m_ui->pointingAprioriSigmaTable, SIGNAL(itemChanged(QTableWidgetItem *)), this, SLOT(validateSigmaValue(QTableWidgetItem *))); // initializations for target body tab // fill target combo box from project Loading Loading @@ -686,6 +709,154 @@ namespace Isis { } /** * @brief updateBundleObservationSolveSettings: This function sets the parameters of * a BundleObservationSolveSettings object by reading user settings from the BOSS * tab, as well as reading in the selected images on the BOSS QTreeView these * BOSS settings are to be applied to. * @param BundleObservationSolveSettings &boss The object which stores user-specified * settings from the BOSS tab. */ void JigsawSetupDialog::updateBundleObservationSolveSettings(BundleObservationSolveSettings &boss) { int ckSolveDegree = m_ui->ckSolveDegreeSpinBox->value(); int spkSolveDegree = m_ui->spkSolveDegreeSpinBox->value(); int ckDegree = m_ui->ckDegreeSpinBox->value(); int spkDegree = m_ui->spkDegreeSpinBox->value(); int instrumentPointingSolveOption=m_ui->pointingComboBox->currentIndex(); int instrumentPositionSolveOption=m_ui->positionComboBox->currentIndex(); BundleObservationSolveSettings::InstrumentPointingSolveOption pointSolvingOption; BundleObservationSolveSettings::InstrumentPositionSolveOption positionSolvingOption; double anglesAprioriSigma(-1.0); double angularVelocityAprioriSigma(-1.0); double angularAccelerationAprioriSigma(-1.0); QList<double> additionalAngularCoefficients; double positionAprioriSigma(-1.0); double velocityAprioriSigma(-1.0); double accelerationAprioriSigma(-1.0); QList<double> additionalPositionCoefficients; bool solveTwist(false); bool solvePolynomialOverExisting(false); bool positionOverHermite(false); if (m_ui->pointingAprioriSigmaTable->item(0,3)) anglesAprioriSigma = m_ui->pointingAprioriSigmaTable->item(0,3)->data(0).toDouble(); if (m_ui->pointingAprioriSigmaTable->item(1,3)) angularVelocityAprioriSigma = m_ui->pointingAprioriSigmaTable->item(1,3)->data(0).toDouble(); if (m_ui->pointingAprioriSigmaTable->item(2,3) ) angularAccelerationAprioriSigma = m_ui->pointingAprioriSigmaTable->item(2,3)->data(0).toDouble(); if (m_ui->positionAprioriSigmaTable->item(0,3)) positionAprioriSigma = m_ui->positionAprioriSigmaTable->item(0,3)->data(0).toDouble(); if (m_ui->positionAprioriSigmaTable->item(1,3)) velocityAprioriSigma = m_ui->positionAprioriSigmaTable->item(1,3)->data(0).toDouble(); if (m_ui->positionAprioriSigmaTable->item(2,3) ) accelerationAprioriSigma = m_ui->positionAprioriSigmaTable->item(2,3)->data(0).toDouble(); //Saving additionalPositional/Angular coefficients (deg >=3) in case they are needed //later. if (spkSolveDegree >2) { for (int i = 3;i <= spkSolveDegree;i++ ) { if (m_ui->positionAprioriSigmaTable->item(i,3)) additionalPositionCoefficients.append(m_ui->positionAprioriSigmaTable->item(i,3)->data(0).toDouble() ); } } if (ckSolveDegree > 2) { for (int i = 3;i <= ckSolveDegree;i++ ) { if (m_ui->pointingAprioriSigmaTable->item(i,3)) additionalAngularCoefficients.append(m_ui->pointingAprioriSigmaTable->item(i,3)->data(0).toDouble() ); } } if (m_ui->twistCheckBox->checkState() == Qt::Checked) solveTwist = true; if (m_ui-> fitOverPointingCheckBox->checkState() == Qt::Checked) solvePolynomialOverExisting = true; switch(instrumentPointingSolveOption) { case 0: pointSolvingOption = BundleObservationSolveSettings::InstrumentPointingSolveOption::NoPointingFactors; break; case 1:pointSolvingOption = BundleObservationSolveSettings::InstrumentPointingSolveOption::AnglesOnly; break; case 2:pointSolvingOption = BundleObservationSolveSettings::InstrumentPointingSolveOption::AnglesVelocity; break; case 3:pointSolvingOption = BundleObservationSolveSettings::InstrumentPointingSolveOption::AnglesVelocityAcceleration; break; case 4:pointSolvingOption = BundleObservationSolveSettings::InstrumentPointingSolveOption::AllPointingCoefficients; break; default: pointSolvingOption = BundleObservationSolveSettings::InstrumentPointingSolveOption::NoPointingFactors; break; } switch(instrumentPositionSolveOption) { case 0: positionSolvingOption = BundleObservationSolveSettings::InstrumentPositionSolveOption::NoPositionFactors; break; case 1:positionSolvingOption = BundleObservationSolveSettings::InstrumentPositionSolveOption::PositionOnly; break; case 2:positionSolvingOption = BundleObservationSolveSettings::InstrumentPositionSolveOption::PositionVelocity; break; case 3:positionSolvingOption = BundleObservationSolveSettings::InstrumentPositionSolveOption::PositionVelocityAcceleration; break; case 4:positionSolvingOption = BundleObservationSolveSettings::InstrumentPositionSolveOption::AllPositionCoefficients; break; default: positionSolvingOption = BundleObservationSolveSettings::InstrumentPositionSolveOption::NoPositionFactors; break; } boss.setInstrumentPositionSettings(positionSolvingOption,spkDegree,spkSolveDegree,positionOverHermite, positionAprioriSigma,velocityAprioriSigma,accelerationAprioriSigma); boss.setInstrumentPointingSettings(pointSolvingOption,solveTwist,ckDegree,ckSolveDegree,solvePolynomialOverExisting, anglesAprioriSigma,angularVelocityAprioriSigma,angularAccelerationAprioriSigma); //What if multiple instrument IDs are represented? boss.setInstrumentId(""); SortFilterProxyModel* proxyModel = (SortFilterProxyModel *)m_ui->treeView->model(); ProjectItemModel* sourceModel = (ProjectItemModel *)proxyModel->sourceModel(); QModelIndexList selectedIndexes = m_ui->treeView->selectionModel()->selectedIndexes(); foreach (QModelIndex index, selectedIndexes) { QModelIndex sourceix = proxyModel->mapToSource(index); ProjectItem * projItem = sourceModel->itemFromIndex(sourceix); if (projItem) { if (projItem->isImage() ) { Image * img = projItem->data().value<Image *>(); boss.addObservationNumber(img->serialNumber() ); //qDebug() << "serial num: " << img->serialNumber(); } } } } QString JigsawSetupDialog::outputControlName() { return QString(m_ui->outputControlNetLineEdit->text()); } Loading Loading @@ -986,53 +1157,6 @@ namespace Isis { } void Isis::JigsawSetupDialog::on_spkSolveDegreeSpinBox_valueChanged(int arg1) { if (arg1 == -1) { m_ui->spkSolveDegreeSpinBox->setSuffix("(NONE)"); m_ui->positionAprioriSigmaTable->setRowCount(0); } m_ui->positionAprioriSigmaTable->setRowCount(arg1+1); m_ui->positionAprioriSigmaTable->resizeColumnsToContents(); if (arg1 == 0) { QTableWidgetItem *twItem = new QTableWidgetItem(); twItem->setText("POSITION"); m_ui->positionAprioriSigmaTable->setItem(arg1,0, twItem); QTableWidgetItem *twItemunits = new QTableWidgetItem(); twItemunits->setText("meters"); //m_ui->positionAprioriSigmaTable->item(arg1,2)->setText("meters"); } else if (arg1 == 1) { QTableWidgetItem *twItem = new QTableWidgetItem(); twItem->setText("VELOCITY"); m_ui->positionAprioriSigmaTable->setItem(arg1,0, twItem); QTableWidgetItem *twItemunits = new QTableWidgetItem(); twItemunits->setText("m/sec"); } else if (arg1 == 2) { QTableWidgetItem *twItem = new QTableWidgetItem(); twItem->setText("ACCELERATION"); m_ui->positionAprioriSigmaTable->setItem(arg1,0, twItem); QTableWidgetItem *twItemunits = new QTableWidgetItem(); twItemunits->setText("m/s^2"); } /* else if (arg1 == 0) { m_ui->spkSolveDegreeSpinBox_2->setSuffix("(POSITION)"); int nRows = m_ui->positionAprioriSigmaTable->rowCount(); m_ui->positionAprioriSigmaTable->insertRow(nRows); } else if (arg1 == 1) m_ui->spkSolveDegreeSpinBox_2->setSuffix("(VELOCITY)"); else if (arg1 == 2) m_ui->spkSolveDegreeSpinBox_2->setSuffix("(ACCELERATION)"); else m_ui->spkSolveDegreeSpinBox_2->setSuffix(""); */ } void Isis::JigsawSetupDialog::on_rightAscensionLineEdit_textChanged(const QString &arg1) { if (!m_ui->rightAscensionLineEdit->hasAcceptableInput()) { m_ui->rightAscensionLineEdit->setStyleSheet("QLineEdit { background-color: red }"); Loading Loading @@ -1248,6 +1372,252 @@ namespace Isis { } /** * Validates the a priori sigma values for a given QTableWidgetItem. * * This will only validate items in the a priori sigma column. Valid a priori sigma values are * "FREE" or any positive double. Items that are invalid will be marked with a red background * color. * * @param QTableWidgetItem* Pointer to the QTableWidgetItem to be validated. */ void JigsawSetupDialog::validateSigmaValue(QTableWidgetItem *item) { // Only validate the "a priori sigma" column if (item->column() != 3) { return; } // FREE is a valid value for the a priori sigma column int free = item->text().compare("FREE", Qt::CaseInsensitive); if (free == 0) { item->setText("FREE"); } // Positive doubles are valid values for the a priori sigma column bool convertSuccess = false; double sigma = item->text().toDouble(&convertSuccess); if ((convertSuccess && sigma >= 0.0) || free == 0) { const QTableWidget *table = item->tableWidget(); // Set background color depending on if the table has alternating row colors and row is odd if (table->alternatingRowColors() && item->row() % 2 != 0) { item->setBackground(table->palette().color(QPalette::AlternateBase)); } else { item->setBackground(table->palette().color(QPalette::Base)); } } else { item->setBackground(Qt::red); } } /** * Slot that listens for changes to the SPK Solve Degree spin box. * * This slot populates the Instrument Position Solve Options table according to the value of the * SPK Solve Degree. Rows are added depending on the degree set, where number of rows added is * equal to the SPK Solve Degree + 1. * * @param int Value the SPK Solve Degree spin box was changed to. */ void JigsawSetupDialog::on_spkSolveDegreeSpinBox_valueChanged(int i) { // number of rows == spkSolveDegree value + 1 (i+1) QTableWidget *table = m_ui->positionAprioriSigmaTable; const int oldRowCount = table->rowCount(); table->setRowCount(i + 1); const int newRowCount = table->rowCount(); if (newRowCount > oldRowCount) { for (int row = oldRowCount; row < newRowCount; row++) { // Headers : coefficient, description, units, a priori sigma QTableWidgetItem *coefficient = new QTableWidgetItem(); coefficient->setFlags(Qt::ItemIsEnabled); coefficient->setText(QString::number(row + 1)); table->setItem(row, 0, coefficient); QTableWidgetItem *description = new QTableWidgetItem(); description->setFlags(Qt::ItemIsEnabled); description->setText("N/A"); table->setItem(row, 1, description); QTableWidgetItem *units = new QTableWidgetItem(); units->setFlags(Qt::ItemIsEnabled); units->setText("m/s^" + QString::number(row)); table->setItem(row, 2, units); QTableWidgetItem *sigma = new QTableWidgetItem(); sigma->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled); sigma->setText("0.0"); table->setItem(row, 3, sigma); // Solve option: spk degree { NONE: -1, POSITION: 0, VELOCITY: 1, ACCELERATION: 2, ALL: 2 } // POSITION if (row == 0) { QTableWidgetItem *description = table->item(0, 1); description->setText("POSITION"); QTableWidgetItem *units = table->item(0, 2); units->setText("meters"); } // VELOCITY else if (row == 1) { QTableWidgetItem *description = table->item(1, 1); description->setText("VELOCITY"); QTableWidgetItem *units = table->item(1, 2); units->setText("m/s"); } // ACCELERATION else if (row == 2) { QTableWidgetItem *description = table->item(2, 1); description->setText("ACCELERATION"); QTableWidgetItem *units = table->item(2, 2); units->setText("m/s^2"); } } } table->resizeColumnToContents(1); table->resizeColumnToContents(2); } /** * Slot that listens for changes to the CK Solve Degree spin box. * * This slot populates the Instrument Pointing Solve Options table according to the value of the * CK Solve Degree. Rows are added depending on the degree set, where number of rows added is * equal to the CK Solve Degree + 1. * * @param int Value the CK Solve Degree spin box was changed to. */ void JigsawSetupDialog::on_ckSolveDegreeSpinBox_valueChanged(int i) { // number of rows == ckSolveDegree value + 1 (i+1) QTableWidget *table = m_ui->pointingAprioriSigmaTable; const int oldRowCount = table->rowCount(); table->setRowCount(i + 1); const int newRowCount = table->rowCount(); if (newRowCount > oldRowCount) { for (int row = oldRowCount; row < newRowCount; row++) { // Headers : coefficient, description, units, a priori sigma QTableWidgetItem *coefficient = new QTableWidgetItem(); coefficient->setFlags(Qt::ItemIsEnabled); coefficient->setText(QString::number(row + 1)); table->setItem(row, 0, coefficient); QTableWidgetItem *description = new QTableWidgetItem(); description->setFlags(Qt::ItemIsEnabled); description->setText("N/A"); table->setItem(row, 1, description); QTableWidgetItem *units = new QTableWidgetItem(); units->setFlags(Qt::ItemIsEnabled); units->setText("deg/s^" + QString::number(row)); table->setItem(row, 2, units); QTableWidgetItem *sigma = new QTableWidgetItem(); sigma->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled); sigma->setText("0.0"); table->setItem(row, 3, sigma); // { NONE: N/A, ANGLES: 0, ANGULAR VELOCITY: 1, ANGULAR ACCELERATION: 2, ALL: 2 } // ANGLES if (row == 0) { QTableWidgetItem *description = table->item(0, 1); description->setText("ANGLES"); QTableWidgetItem *units = table->item(0, 2); units->setText("degrees"); } // VELOCITY if (row == 1) { QTableWidgetItem *description = table->item(1, 1); description->setText("ANGULAR VELOCITY"); QTableWidgetItem *units = table->item(1, 2); units->setText("deg/s"); } // ACCELERATION if (row == 2) { QTableWidgetItem *description = table->item(2, 1); description->setText("ANGULAR ACCELERATION"); QTableWidgetItem *units = table->item(2, 2); units->setText("deg/s^2"); } } } table->resizeColumnToContents(1); table->resizeColumnToContents(2); } /** * Slot that listens for when the Instrument Position Solve Option combobox changes. * * This slot updates the value of the SPK Solve Degree spin box according to which solve position * option is selected. This slot also disables the SPK spin boxes whenever a solve * position that is not ALL is selected. * * @param const QString & Reference to the value that the position option combobox was changed to. */ void JigsawSetupDialog::on_positionComboBox_currentIndexChanged(const QString &arg1) { int solveIndex = m_ui->positionComboBox->currentIndex(); QList<QSpinBox *> spinBoxes{m_ui->spkSolveDegreeSpinBox, m_ui->spkDegreeSpinBox}; for (auto &spinBox : spinBoxes) { // ALL enables the solve degree spin box, but does not increase the degree // Below shows the corresponding degree for each of the solve options: // NONE = -1; ANGLES = 0; VELOCITY = 1; ACCELERATION = 2; ALL = 2 if (arg1 == "ALL") { spinBox->setValue(solveIndex - 2); spinBox->setEnabled(true); } else { spinBox->setValue(solveIndex - 1); spinBox->setEnabled(false); } } } /** * Slot that listens for when the Instrument Pointing Solve Option combobox changes. * * This slot updates the value of the CK Solve Degree spin box according to which solve pointing * option is selected. This slot also disables the CK spin boxes whenever a solve * pointing that is not ALL is selected. * * @param const QString & Reference to the value that the pointing option combobox was changed to. */ void JigsawSetupDialog::on_pointingComboBox_currentIndexChanged(const QString &arg1) { int solveIndex = m_ui->pointingComboBox->currentIndex(); QList<QSpinBox *> spinBoxes{m_ui->ckSolveDegreeSpinBox, m_ui->ckDegreeSpinBox}; for (auto &spinBox : spinBoxes) { // ALL enables the solve degree spin box, but does not increase the degree // Below shows the corresponding degree for each of the solve options: // NONE = -1; ANGLES = 0; ANGULAR VELOCITY = 1; ANGULAR ACCELERATION = 2; ALL = 2 if (arg1 == "ALL") { spinBox->setValue(solveIndex - 2); spinBox->setEnabled(true); } else { spinBox->setValue(solveIndex - 1); spinBox->setEnabled(false); } } } void JigsawSetupDialog::createObservationSolveSettingsTreeView() { QList<ProjectItem *> selectedBOSSItems = m_project->directory()->model()->selectedBOSSImages(); Loading isis/src/qisis/objs/JigsawSetupDialog/JigsawSetupDialog.h +17 −2 Original line number Diff line number Diff line Loading @@ -10,9 +10,10 @@ namespace Ui { } class QItemSelection; class QTableWidgetItem; namespace Isis { class BundleObservationSolveSettings; class Project; class ProjectItem; class Control; Loading Loading @@ -70,6 +71,12 @@ namespace Isis { * (BOSS) tab for displaying user-selected images from the main Project * treeview. All changes were made in the * createObservationSolveSettingsTreeView() function. References #497. * @history 2018-06-25 Ian Humphrey - Implemented the position and pointing a priori sigma * tables in the observation solve settings tab. References #497. * @history 2018-06-26 Tyler Wilson - Added the function * updateBundleObservationSolveSettings(BundleObservationSolveSettings &) * which grabs BOSS settings from the JSD BOSS tab for selected images * in the BOSS QTreeView and saves them in a BOSS object. * @history 2018-06-26 Christopher Combs - Implemented pseudocode in on_applySettings... method. * References #497. */ Loading Loading @@ -134,6 +141,7 @@ namespace Isis { void on_aRadiusLineEdit_textChanged(const QString &arg1); void on_targetBodyComboBox_currentIndexChanged(int index); void on_spkSolveDegreeSpinBox_valueChanged(int arg1); void on_ckSolveDegreeSpinBox_valueChanged(int arg1); void on_rightAscensionLineEdit_textChanged(const QString &arg1); void on_declinationLineEdit_textChanged(const QString &arg1); void on_rightAscensionVelocityLineEdit_textChanged(const QString &arg1); Loading @@ -143,6 +151,12 @@ namespace Isis { void on_applySettingsPushButton_clicked(); void on_positionComboBox_currentIndexChanged(const QString &arg1); void on_pointingComboBox_currentIndexChanged(const QString &arg1); void validateSigmaValue(QTableWidgetItem *); public slots: void slotTextChanged(const QString &text); void checkIsValid(); Loading @@ -153,6 +167,7 @@ namespace Isis { void fillFromSettings(const BundleSettingsQsp settings); void showTargetParametersGroupBox(); void hideTargetParametersGroupBox(); void updateBundleObservationSolveSettings(BundleObservationSolveSettings &boss); void createObservationSolveSettingsTreeView(); Loading isis/src/qisis/objs/JigsawSetupDialog/JigsawSetupDialog.ui +169 −133 File changed.Preview size limit exceeded, changes collapsed. Show changes isis/src/qisis/objs/ProjectItemModel/ProjectItemModel.cpp +32 −4 Original line number Diff line number Diff line Loading @@ -190,9 +190,11 @@ namespace Isis { QItemSelection selection = selectionModel()->selection(); QList<ProjectItem *> items; QModelIndexList indices = selection.indexes(); //Query the selected items to see if they have children foreach ( QModelIndex ix, selection.indexes() ) { foreach ( QModelIndex ix, indices ) { ProjectItem *item = this->itemFromIndex(ix); Loading @@ -206,16 +208,42 @@ namespace Isis { return items; } //If the selected ImageList has children, include all of the children. //If the selected ImageList has children, we have to handle //the case where some of the children are selected, or //the possibility that the user wants all of the children selected. if (this->hasChildren(ix)) { //If the node has children, loop through all of them //and add them to selected items. bool childrenSelected(false); int numChildren = this->rowCount(ix); //First loop through the children to see if any of them are also selected for (int i = 0; i < numChildren;i++) { QModelIndex ixchild = this->index(i,0,ix); if (indices.contains(ixchild) ){ childrenSelected=true; break; } } //If they are, then add them to selected items if (childrenSelected) { for (int i =0;i < numChildren;i++) { QModelIndex ixchild = this->index(i,0,ix); if (indices.contains(ixchild)) items.append(this->itemFromIndex(ixchild )); } //end for } } //No children selected, so we are assuming that the user //wanted to select all of the children under the parent. else { for (int i =0;i < numChildren;i++) { QModelIndex ixchild = this->index(i,0,ix); items.append(this->itemFromIndex(ixchild )); } } }//end if //Append the parent of any selected child. This is so Loading isis/src/qisis/objs/ProjectItemModel/ProjectItemModel.h +5 −1 Original line number Diff line number Diff line Loading @@ -134,7 +134,11 @@ namespace Isis { * refinement of selectedItems and is used by the JigsawSetupDialog * Bundle Observation Solve Settings (BOSS) tab when displaying a * subset of user-selected images. References #497 * * @history 2018-06-24 Tyler Wilson - Fixed an edge-case scenario in the selection criteria for * selectedBOSSImages(). If a user selected an image list and some * (but not all) of the images within that list, the function returned * all of the images in the list and not just the selected ones. * References #497. */ class ProjectItemModel : public QStandardItemModel { Loading Loading
isis/src/qisis/objs/JigsawSetupDialog/JigsawSetupDialog.cpp +423 −53 Original line number Diff line number Diff line Loading @@ -10,10 +10,13 @@ #include <QStandardItemModel> #include <QItemSelection> #include "BundleObservationSolveSettings.h" #include "BundleSolutionInfo.h" #include "BundleSettings.h" #include "BundleTargetBody.h" #include "Control.h" #include "Cube.h" #include "Image.h" #include "IString.h" #include "MaximumLikelihoodWFunctions.h" #include "Project.h" Loading Loading @@ -98,20 +101,40 @@ namespace Isis { // Update setup dialog with settings from any active (current) settings in jigsaw dialog. // initializations for observation solve settings tab createObservationSolveSettingsTreeView(); m_ui->spkSolveDegreeSpinBox->setValue(-1); // Populate the solve option comboboxes const QStringList positionOptions{"NONE", "POSITION", "VELOCITY", "ACCELERATION", "ALL"}; m_ui->positionComboBox->insertItems(0, positionOptions); m_ui->positionComboBox->setCurrentIndex(0); const QStringList pointingOptions{"NONE", "ANGLES", "VELOCITY", "ACCELERATION", "ALL"}; m_ui->pointingComboBox->insertItems(0, pointingOptions); m_ui->pointingComboBox->setCurrentIndex(0); // The degree solve options' minimums are -1 (set in ui file), make the -1's display as N/A m_ui->spkSolveDegreeSpinBox->setSpecialValueText("N/A"); m_ui->ckSolveDegreeSpinBox->setSpecialValueText("N/A"); QStringList tableHeaders; tableHeaders << "coefficients" << "a priori sigma" << "units"; tableHeaders << "coefficients" << "description" << "units" << "a priori sigma"; m_ui->positionAprioriSigmaTable->setHorizontalHeaderLabels(tableHeaders); m_ui->positionAprioriSigmaTable->setColumnWidth(0, fontMetrics().width(tableHeaders.at(0))); m_ui->positionAprioriSigmaTable->setColumnWidth(1, fontMetrics().width(tableHeaders.at(1))); m_ui->positionAprioriSigmaTable->setColumnWidth(2, fontMetrics().width(tableHeaders.at(2))); m_ui->positionAprioriSigmaTable->setColumnWidth(0, fontMetrics().width(tableHeaders.at(0)) + 10); m_ui->positionAprioriSigmaTable->setColumnWidth(1, fontMetrics().width(tableHeaders.at(1)) + 10); m_ui->positionAprioriSigmaTable->setColumnWidth(2, fontMetrics().width(tableHeaders.at(2)) + 10); m_ui->positionAprioriSigmaTable->setColumnWidth(3, fontMetrics().width(tableHeaders.at(3)) + 10); m_ui->pointingAprioriSigmaTable->setHorizontalHeaderLabels(tableHeaders); // Add validators to the tables in the observation solve settings tab to validate the a priori // sigma items connect(m_ui->positionAprioriSigmaTable, SIGNAL(itemChanged(QTableWidgetItem *)), this, SLOT(validateSigmaValue(QTableWidgetItem *))); connect(m_ui->pointingAprioriSigmaTable, SIGNAL(itemChanged(QTableWidgetItem *)), this, SLOT(validateSigmaValue(QTableWidgetItem *))); // initializations for target body tab // fill target combo box from project Loading Loading @@ -686,6 +709,154 @@ namespace Isis { } /** * @brief updateBundleObservationSolveSettings: This function sets the parameters of * a BundleObservationSolveSettings object by reading user settings from the BOSS * tab, as well as reading in the selected images on the BOSS QTreeView these * BOSS settings are to be applied to. * @param BundleObservationSolveSettings &boss The object which stores user-specified * settings from the BOSS tab. */ void JigsawSetupDialog::updateBundleObservationSolveSettings(BundleObservationSolveSettings &boss) { int ckSolveDegree = m_ui->ckSolveDegreeSpinBox->value(); int spkSolveDegree = m_ui->spkSolveDegreeSpinBox->value(); int ckDegree = m_ui->ckDegreeSpinBox->value(); int spkDegree = m_ui->spkDegreeSpinBox->value(); int instrumentPointingSolveOption=m_ui->pointingComboBox->currentIndex(); int instrumentPositionSolveOption=m_ui->positionComboBox->currentIndex(); BundleObservationSolveSettings::InstrumentPointingSolveOption pointSolvingOption; BundleObservationSolveSettings::InstrumentPositionSolveOption positionSolvingOption; double anglesAprioriSigma(-1.0); double angularVelocityAprioriSigma(-1.0); double angularAccelerationAprioriSigma(-1.0); QList<double> additionalAngularCoefficients; double positionAprioriSigma(-1.0); double velocityAprioriSigma(-1.0); double accelerationAprioriSigma(-1.0); QList<double> additionalPositionCoefficients; bool solveTwist(false); bool solvePolynomialOverExisting(false); bool positionOverHermite(false); if (m_ui->pointingAprioriSigmaTable->item(0,3)) anglesAprioriSigma = m_ui->pointingAprioriSigmaTable->item(0,3)->data(0).toDouble(); if (m_ui->pointingAprioriSigmaTable->item(1,3)) angularVelocityAprioriSigma = m_ui->pointingAprioriSigmaTable->item(1,3)->data(0).toDouble(); if (m_ui->pointingAprioriSigmaTable->item(2,3) ) angularAccelerationAprioriSigma = m_ui->pointingAprioriSigmaTable->item(2,3)->data(0).toDouble(); if (m_ui->positionAprioriSigmaTable->item(0,3)) positionAprioriSigma = m_ui->positionAprioriSigmaTable->item(0,3)->data(0).toDouble(); if (m_ui->positionAprioriSigmaTable->item(1,3)) velocityAprioriSigma = m_ui->positionAprioriSigmaTable->item(1,3)->data(0).toDouble(); if (m_ui->positionAprioriSigmaTable->item(2,3) ) accelerationAprioriSigma = m_ui->positionAprioriSigmaTable->item(2,3)->data(0).toDouble(); //Saving additionalPositional/Angular coefficients (deg >=3) in case they are needed //later. if (spkSolveDegree >2) { for (int i = 3;i <= spkSolveDegree;i++ ) { if (m_ui->positionAprioriSigmaTable->item(i,3)) additionalPositionCoefficients.append(m_ui->positionAprioriSigmaTable->item(i,3)->data(0).toDouble() ); } } if (ckSolveDegree > 2) { for (int i = 3;i <= ckSolveDegree;i++ ) { if (m_ui->pointingAprioriSigmaTable->item(i,3)) additionalAngularCoefficients.append(m_ui->pointingAprioriSigmaTable->item(i,3)->data(0).toDouble() ); } } if (m_ui->twistCheckBox->checkState() == Qt::Checked) solveTwist = true; if (m_ui-> fitOverPointingCheckBox->checkState() == Qt::Checked) solvePolynomialOverExisting = true; switch(instrumentPointingSolveOption) { case 0: pointSolvingOption = BundleObservationSolveSettings::InstrumentPointingSolveOption::NoPointingFactors; break; case 1:pointSolvingOption = BundleObservationSolveSettings::InstrumentPointingSolveOption::AnglesOnly; break; case 2:pointSolvingOption = BundleObservationSolveSettings::InstrumentPointingSolveOption::AnglesVelocity; break; case 3:pointSolvingOption = BundleObservationSolveSettings::InstrumentPointingSolveOption::AnglesVelocityAcceleration; break; case 4:pointSolvingOption = BundleObservationSolveSettings::InstrumentPointingSolveOption::AllPointingCoefficients; break; default: pointSolvingOption = BundleObservationSolveSettings::InstrumentPointingSolveOption::NoPointingFactors; break; } switch(instrumentPositionSolveOption) { case 0: positionSolvingOption = BundleObservationSolveSettings::InstrumentPositionSolveOption::NoPositionFactors; break; case 1:positionSolvingOption = BundleObservationSolveSettings::InstrumentPositionSolveOption::PositionOnly; break; case 2:positionSolvingOption = BundleObservationSolveSettings::InstrumentPositionSolveOption::PositionVelocity; break; case 3:positionSolvingOption = BundleObservationSolveSettings::InstrumentPositionSolveOption::PositionVelocityAcceleration; break; case 4:positionSolvingOption = BundleObservationSolveSettings::InstrumentPositionSolveOption::AllPositionCoefficients; break; default: positionSolvingOption = BundleObservationSolveSettings::InstrumentPositionSolveOption::NoPositionFactors; break; } boss.setInstrumentPositionSettings(positionSolvingOption,spkDegree,spkSolveDegree,positionOverHermite, positionAprioriSigma,velocityAprioriSigma,accelerationAprioriSigma); boss.setInstrumentPointingSettings(pointSolvingOption,solveTwist,ckDegree,ckSolveDegree,solvePolynomialOverExisting, anglesAprioriSigma,angularVelocityAprioriSigma,angularAccelerationAprioriSigma); //What if multiple instrument IDs are represented? boss.setInstrumentId(""); SortFilterProxyModel* proxyModel = (SortFilterProxyModel *)m_ui->treeView->model(); ProjectItemModel* sourceModel = (ProjectItemModel *)proxyModel->sourceModel(); QModelIndexList selectedIndexes = m_ui->treeView->selectionModel()->selectedIndexes(); foreach (QModelIndex index, selectedIndexes) { QModelIndex sourceix = proxyModel->mapToSource(index); ProjectItem * projItem = sourceModel->itemFromIndex(sourceix); if (projItem) { if (projItem->isImage() ) { Image * img = projItem->data().value<Image *>(); boss.addObservationNumber(img->serialNumber() ); //qDebug() << "serial num: " << img->serialNumber(); } } } } QString JigsawSetupDialog::outputControlName() { return QString(m_ui->outputControlNetLineEdit->text()); } Loading Loading @@ -986,53 +1157,6 @@ namespace Isis { } void Isis::JigsawSetupDialog::on_spkSolveDegreeSpinBox_valueChanged(int arg1) { if (arg1 == -1) { m_ui->spkSolveDegreeSpinBox->setSuffix("(NONE)"); m_ui->positionAprioriSigmaTable->setRowCount(0); } m_ui->positionAprioriSigmaTable->setRowCount(arg1+1); m_ui->positionAprioriSigmaTable->resizeColumnsToContents(); if (arg1 == 0) { QTableWidgetItem *twItem = new QTableWidgetItem(); twItem->setText("POSITION"); m_ui->positionAprioriSigmaTable->setItem(arg1,0, twItem); QTableWidgetItem *twItemunits = new QTableWidgetItem(); twItemunits->setText("meters"); //m_ui->positionAprioriSigmaTable->item(arg1,2)->setText("meters"); } else if (arg1 == 1) { QTableWidgetItem *twItem = new QTableWidgetItem(); twItem->setText("VELOCITY"); m_ui->positionAprioriSigmaTable->setItem(arg1,0, twItem); QTableWidgetItem *twItemunits = new QTableWidgetItem(); twItemunits->setText("m/sec"); } else if (arg1 == 2) { QTableWidgetItem *twItem = new QTableWidgetItem(); twItem->setText("ACCELERATION"); m_ui->positionAprioriSigmaTable->setItem(arg1,0, twItem); QTableWidgetItem *twItemunits = new QTableWidgetItem(); twItemunits->setText("m/s^2"); } /* else if (arg1 == 0) { m_ui->spkSolveDegreeSpinBox_2->setSuffix("(POSITION)"); int nRows = m_ui->positionAprioriSigmaTable->rowCount(); m_ui->positionAprioriSigmaTable->insertRow(nRows); } else if (arg1 == 1) m_ui->spkSolveDegreeSpinBox_2->setSuffix("(VELOCITY)"); else if (arg1 == 2) m_ui->spkSolveDegreeSpinBox_2->setSuffix("(ACCELERATION)"); else m_ui->spkSolveDegreeSpinBox_2->setSuffix(""); */ } void Isis::JigsawSetupDialog::on_rightAscensionLineEdit_textChanged(const QString &arg1) { if (!m_ui->rightAscensionLineEdit->hasAcceptableInput()) { m_ui->rightAscensionLineEdit->setStyleSheet("QLineEdit { background-color: red }"); Loading Loading @@ -1248,6 +1372,252 @@ namespace Isis { } /** * Validates the a priori sigma values for a given QTableWidgetItem. * * This will only validate items in the a priori sigma column. Valid a priori sigma values are * "FREE" or any positive double. Items that are invalid will be marked with a red background * color. * * @param QTableWidgetItem* Pointer to the QTableWidgetItem to be validated. */ void JigsawSetupDialog::validateSigmaValue(QTableWidgetItem *item) { // Only validate the "a priori sigma" column if (item->column() != 3) { return; } // FREE is a valid value for the a priori sigma column int free = item->text().compare("FREE", Qt::CaseInsensitive); if (free == 0) { item->setText("FREE"); } // Positive doubles are valid values for the a priori sigma column bool convertSuccess = false; double sigma = item->text().toDouble(&convertSuccess); if ((convertSuccess && sigma >= 0.0) || free == 0) { const QTableWidget *table = item->tableWidget(); // Set background color depending on if the table has alternating row colors and row is odd if (table->alternatingRowColors() && item->row() % 2 != 0) { item->setBackground(table->palette().color(QPalette::AlternateBase)); } else { item->setBackground(table->palette().color(QPalette::Base)); } } else { item->setBackground(Qt::red); } } /** * Slot that listens for changes to the SPK Solve Degree spin box. * * This slot populates the Instrument Position Solve Options table according to the value of the * SPK Solve Degree. Rows are added depending on the degree set, where number of rows added is * equal to the SPK Solve Degree + 1. * * @param int Value the SPK Solve Degree spin box was changed to. */ void JigsawSetupDialog::on_spkSolveDegreeSpinBox_valueChanged(int i) { // number of rows == spkSolveDegree value + 1 (i+1) QTableWidget *table = m_ui->positionAprioriSigmaTable; const int oldRowCount = table->rowCount(); table->setRowCount(i + 1); const int newRowCount = table->rowCount(); if (newRowCount > oldRowCount) { for (int row = oldRowCount; row < newRowCount; row++) { // Headers : coefficient, description, units, a priori sigma QTableWidgetItem *coefficient = new QTableWidgetItem(); coefficient->setFlags(Qt::ItemIsEnabled); coefficient->setText(QString::number(row + 1)); table->setItem(row, 0, coefficient); QTableWidgetItem *description = new QTableWidgetItem(); description->setFlags(Qt::ItemIsEnabled); description->setText("N/A"); table->setItem(row, 1, description); QTableWidgetItem *units = new QTableWidgetItem(); units->setFlags(Qt::ItemIsEnabled); units->setText("m/s^" + QString::number(row)); table->setItem(row, 2, units); QTableWidgetItem *sigma = new QTableWidgetItem(); sigma->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled); sigma->setText("0.0"); table->setItem(row, 3, sigma); // Solve option: spk degree { NONE: -1, POSITION: 0, VELOCITY: 1, ACCELERATION: 2, ALL: 2 } // POSITION if (row == 0) { QTableWidgetItem *description = table->item(0, 1); description->setText("POSITION"); QTableWidgetItem *units = table->item(0, 2); units->setText("meters"); } // VELOCITY else if (row == 1) { QTableWidgetItem *description = table->item(1, 1); description->setText("VELOCITY"); QTableWidgetItem *units = table->item(1, 2); units->setText("m/s"); } // ACCELERATION else if (row == 2) { QTableWidgetItem *description = table->item(2, 1); description->setText("ACCELERATION"); QTableWidgetItem *units = table->item(2, 2); units->setText("m/s^2"); } } } table->resizeColumnToContents(1); table->resizeColumnToContents(2); } /** * Slot that listens for changes to the CK Solve Degree spin box. * * This slot populates the Instrument Pointing Solve Options table according to the value of the * CK Solve Degree. Rows are added depending on the degree set, where number of rows added is * equal to the CK Solve Degree + 1. * * @param int Value the CK Solve Degree spin box was changed to. */ void JigsawSetupDialog::on_ckSolveDegreeSpinBox_valueChanged(int i) { // number of rows == ckSolveDegree value + 1 (i+1) QTableWidget *table = m_ui->pointingAprioriSigmaTable; const int oldRowCount = table->rowCount(); table->setRowCount(i + 1); const int newRowCount = table->rowCount(); if (newRowCount > oldRowCount) { for (int row = oldRowCount; row < newRowCount; row++) { // Headers : coefficient, description, units, a priori sigma QTableWidgetItem *coefficient = new QTableWidgetItem(); coefficient->setFlags(Qt::ItemIsEnabled); coefficient->setText(QString::number(row + 1)); table->setItem(row, 0, coefficient); QTableWidgetItem *description = new QTableWidgetItem(); description->setFlags(Qt::ItemIsEnabled); description->setText("N/A"); table->setItem(row, 1, description); QTableWidgetItem *units = new QTableWidgetItem(); units->setFlags(Qt::ItemIsEnabled); units->setText("deg/s^" + QString::number(row)); table->setItem(row, 2, units); QTableWidgetItem *sigma = new QTableWidgetItem(); sigma->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled); sigma->setText("0.0"); table->setItem(row, 3, sigma); // { NONE: N/A, ANGLES: 0, ANGULAR VELOCITY: 1, ANGULAR ACCELERATION: 2, ALL: 2 } // ANGLES if (row == 0) { QTableWidgetItem *description = table->item(0, 1); description->setText("ANGLES"); QTableWidgetItem *units = table->item(0, 2); units->setText("degrees"); } // VELOCITY if (row == 1) { QTableWidgetItem *description = table->item(1, 1); description->setText("ANGULAR VELOCITY"); QTableWidgetItem *units = table->item(1, 2); units->setText("deg/s"); } // ACCELERATION if (row == 2) { QTableWidgetItem *description = table->item(2, 1); description->setText("ANGULAR ACCELERATION"); QTableWidgetItem *units = table->item(2, 2); units->setText("deg/s^2"); } } } table->resizeColumnToContents(1); table->resizeColumnToContents(2); } /** * Slot that listens for when the Instrument Position Solve Option combobox changes. * * This slot updates the value of the SPK Solve Degree spin box according to which solve position * option is selected. This slot also disables the SPK spin boxes whenever a solve * position that is not ALL is selected. * * @param const QString & Reference to the value that the position option combobox was changed to. */ void JigsawSetupDialog::on_positionComboBox_currentIndexChanged(const QString &arg1) { int solveIndex = m_ui->positionComboBox->currentIndex(); QList<QSpinBox *> spinBoxes{m_ui->spkSolveDegreeSpinBox, m_ui->spkDegreeSpinBox}; for (auto &spinBox : spinBoxes) { // ALL enables the solve degree spin box, but does not increase the degree // Below shows the corresponding degree for each of the solve options: // NONE = -1; ANGLES = 0; VELOCITY = 1; ACCELERATION = 2; ALL = 2 if (arg1 == "ALL") { spinBox->setValue(solveIndex - 2); spinBox->setEnabled(true); } else { spinBox->setValue(solveIndex - 1); spinBox->setEnabled(false); } } } /** * Slot that listens for when the Instrument Pointing Solve Option combobox changes. * * This slot updates the value of the CK Solve Degree spin box according to which solve pointing * option is selected. This slot also disables the CK spin boxes whenever a solve * pointing that is not ALL is selected. * * @param const QString & Reference to the value that the pointing option combobox was changed to. */ void JigsawSetupDialog::on_pointingComboBox_currentIndexChanged(const QString &arg1) { int solveIndex = m_ui->pointingComboBox->currentIndex(); QList<QSpinBox *> spinBoxes{m_ui->ckSolveDegreeSpinBox, m_ui->ckDegreeSpinBox}; for (auto &spinBox : spinBoxes) { // ALL enables the solve degree spin box, but does not increase the degree // Below shows the corresponding degree for each of the solve options: // NONE = -1; ANGLES = 0; ANGULAR VELOCITY = 1; ANGULAR ACCELERATION = 2; ALL = 2 if (arg1 == "ALL") { spinBox->setValue(solveIndex - 2); spinBox->setEnabled(true); } else { spinBox->setValue(solveIndex - 1); spinBox->setEnabled(false); } } } void JigsawSetupDialog::createObservationSolveSettingsTreeView() { QList<ProjectItem *> selectedBOSSItems = m_project->directory()->model()->selectedBOSSImages(); Loading
isis/src/qisis/objs/JigsawSetupDialog/JigsawSetupDialog.h +17 −2 Original line number Diff line number Diff line Loading @@ -10,9 +10,10 @@ namespace Ui { } class QItemSelection; class QTableWidgetItem; namespace Isis { class BundleObservationSolveSettings; class Project; class ProjectItem; class Control; Loading Loading @@ -70,6 +71,12 @@ namespace Isis { * (BOSS) tab for displaying user-selected images from the main Project * treeview. All changes were made in the * createObservationSolveSettingsTreeView() function. References #497. * @history 2018-06-25 Ian Humphrey - Implemented the position and pointing a priori sigma * tables in the observation solve settings tab. References #497. * @history 2018-06-26 Tyler Wilson - Added the function * updateBundleObservationSolveSettings(BundleObservationSolveSettings &) * which grabs BOSS settings from the JSD BOSS tab for selected images * in the BOSS QTreeView and saves them in a BOSS object. * @history 2018-06-26 Christopher Combs - Implemented pseudocode in on_applySettings... method. * References #497. */ Loading Loading @@ -134,6 +141,7 @@ namespace Isis { void on_aRadiusLineEdit_textChanged(const QString &arg1); void on_targetBodyComboBox_currentIndexChanged(int index); void on_spkSolveDegreeSpinBox_valueChanged(int arg1); void on_ckSolveDegreeSpinBox_valueChanged(int arg1); void on_rightAscensionLineEdit_textChanged(const QString &arg1); void on_declinationLineEdit_textChanged(const QString &arg1); void on_rightAscensionVelocityLineEdit_textChanged(const QString &arg1); Loading @@ -143,6 +151,12 @@ namespace Isis { void on_applySettingsPushButton_clicked(); void on_positionComboBox_currentIndexChanged(const QString &arg1); void on_pointingComboBox_currentIndexChanged(const QString &arg1); void validateSigmaValue(QTableWidgetItem *); public slots: void slotTextChanged(const QString &text); void checkIsValid(); Loading @@ -153,6 +167,7 @@ namespace Isis { void fillFromSettings(const BundleSettingsQsp settings); void showTargetParametersGroupBox(); void hideTargetParametersGroupBox(); void updateBundleObservationSolveSettings(BundleObservationSolveSettings &boss); void createObservationSolveSettingsTreeView(); Loading
isis/src/qisis/objs/JigsawSetupDialog/JigsawSetupDialog.ui +169 −133 File changed.Preview size limit exceeded, changes collapsed. Show changes
isis/src/qisis/objs/ProjectItemModel/ProjectItemModel.cpp +32 −4 Original line number Diff line number Diff line Loading @@ -190,9 +190,11 @@ namespace Isis { QItemSelection selection = selectionModel()->selection(); QList<ProjectItem *> items; QModelIndexList indices = selection.indexes(); //Query the selected items to see if they have children foreach ( QModelIndex ix, selection.indexes() ) { foreach ( QModelIndex ix, indices ) { ProjectItem *item = this->itemFromIndex(ix); Loading @@ -206,16 +208,42 @@ namespace Isis { return items; } //If the selected ImageList has children, include all of the children. //If the selected ImageList has children, we have to handle //the case where some of the children are selected, or //the possibility that the user wants all of the children selected. if (this->hasChildren(ix)) { //If the node has children, loop through all of them //and add them to selected items. bool childrenSelected(false); int numChildren = this->rowCount(ix); //First loop through the children to see if any of them are also selected for (int i = 0; i < numChildren;i++) { QModelIndex ixchild = this->index(i,0,ix); if (indices.contains(ixchild) ){ childrenSelected=true; break; } } //If they are, then add them to selected items if (childrenSelected) { for (int i =0;i < numChildren;i++) { QModelIndex ixchild = this->index(i,0,ix); if (indices.contains(ixchild)) items.append(this->itemFromIndex(ixchild )); } //end for } } //No children selected, so we are assuming that the user //wanted to select all of the children under the parent. else { for (int i =0;i < numChildren;i++) { QModelIndex ixchild = this->index(i,0,ix); items.append(this->itemFromIndex(ixchild )); } } }//end if //Append the parent of any selected child. This is so Loading
isis/src/qisis/objs/ProjectItemModel/ProjectItemModel.h +5 −1 Original line number Diff line number Diff line Loading @@ -134,7 +134,11 @@ namespace Isis { * refinement of selectedItems and is used by the JigsawSetupDialog * Bundle Observation Solve Settings (BOSS) tab when displaying a * subset of user-selected images. References #497 * * @history 2018-06-24 Tyler Wilson - Fixed an edge-case scenario in the selection criteria for * selectedBOSSImages(). If a user selected an image list and some * (but not all) of the images within that list, the function returned * all of the images in the list and not just the selected ones. * References #497. */ class ProjectItemModel : public QStandardItemModel { Loading