ExportOptionsDlg::ExportOptionsDlg(ExporterResource& pExporter, QWidget* pParent) :
   QDialog(pParent),
   mpExporter(pExporter),
   mpTabWidget(NULL),
   mpSubsetPage(NULL),
   mpExporterPage(NULL)
{
   // Options widget
   QStackedWidget* pStack = new QStackedWidget(this);

   // Subset page
   RasterElement* pRasterElement = dynamic_cast<RasterElement*>(mpExporter->getItem());
   RasterFileDescriptor* pRasterWholeCubeFileDescriptor = NULL;
   RasterDataDescriptor* pRasterOrgDataDescriptor = NULL;
   if (pRasterElement != NULL)
   {
      pRasterOrgDataDescriptor = dynamic_cast<RasterDataDescriptor*>(pRasterElement->getDataDescriptor());
      if (pRasterOrgDataDescriptor != NULL)
      {
         // we are creating a file descriptor for export from the original cube, because the SubsetWidget
         // uses DimensionDescriptor::operator= compare's to determine selection which dictate that on-disk,
         // original and active numbers need to be identical, this guarantees that DimensionDescriptors will
         // compare correctly.
         pRasterWholeCubeFileDescriptor = dynamic_cast<RasterFileDescriptor*>(
            RasterUtilities::generateFileDescriptorForExport(pRasterOrgDataDescriptor, "foobar"));
      }
   }
   RasterFileDescriptor* pRasterFileDescriptor = dynamic_cast<RasterFileDescriptor*>(mpExporter->getFileDescriptor());
   if ((pRasterFileDescriptor != NULL) && (pRasterWholeCubeFileDescriptor != NULL) &&
      (pRasterOrgDataDescriptor != NULL))
   {
      mpSubsetPage = new SubsetWidget();
      mpSubsetPage->setExportMode(true);

      // Rows
      const vector<DimensionDescriptor>& orgRows = pRasterWholeCubeFileDescriptor->getRows();
      const vector<DimensionDescriptor>& selectedRows = pRasterFileDescriptor->getRows();
      mpSubsetPage->setRows(orgRows, selectedRows);

      // Columns
      const vector<DimensionDescriptor>& orgColumns = pRasterWholeCubeFileDescriptor->getColumns();
      const vector<DimensionDescriptor>& selectedColumns = pRasterFileDescriptor->getColumns();
      mpSubsetPage->setColumns(orgColumns, selectedColumns);

      // Bands
      const vector<DimensionDescriptor>& orgBands = pRasterWholeCubeFileDescriptor->getBands();
      const vector<DimensionDescriptor>& selectedBands = pRasterFileDescriptor->getBands();
      vector<string> bandNames = RasterUtilities::getBandNames(pRasterOrgDataDescriptor);
      mpSubsetPage->setBands(orgBands, bandNames, selectedBands);

      // Initial bad band file directory
      QString strDirectory;

      string filename = pRasterFileDescriptor->getFilename();
      if (filename.empty() == false)
      {
         QFileInfo fileInfo(QString::fromStdString(filename));
         strDirectory = fileInfo.absolutePath();
      }

      mpSubsetPage->setBadBandFileDirectory(strDirectory);
   }

   // Exporter page
   if (mpExporter->getPlugIn() != NULL)
   {
      mpExporterPage = mpExporter->getExportOptionsWidget();
   }

   // Horizontal line
   QFrame* pLine = new QFrame(this);
   pLine->setFrameStyle(QFrame::HLine | QFrame::Sunken);

   // Buttons
   QDialogButtonBox* pButtonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel,
      Qt::Horizontal, this);

   // Layout
   QVBoxLayout* pLayout = new QVBoxLayout(this);
   pLayout->setMargin(10);
   pLayout->setSpacing(10);
   pLayout->addWidget(pStack, 10);
   pLayout->addWidget(pLine);
   pLayout->addWidget(pButtonBox);

   // Initialization
   QString strWindowTitle = "Export Options";

   SessionItem* pSessionItem = mpExporter->getItem();
   if (pSessionItem != NULL)
   {
      string name = pSessionItem->getDisplayName();
      if (name.empty() == true)
      {
         name = pSessionItem->getName();
      }

      if (name.empty() == false)
      {
         strWindowTitle += ": " + QString::fromStdString(name);
      }
   }

   setWindowTitle(strWindowTitle);
   setModal(true);

   if ((mpSubsetPage != NULL) || (mpExporterPage != NULL))
   {
      QWidget* pSubsetWidget = NULL;
      if (mpSubsetPage != NULL)
      {
         pSubsetWidget = new QWidget();
         mpSubsetPage->setParent(pSubsetWidget);

         QVBoxLayout* pSubsetLayout = new QVBoxLayout(pSubsetWidget);
         if (mpExporterPage != NULL)
         {
            pSubsetLayout->setMargin(10);
         }
         else
         {
            pSubsetLayout->setMargin(0);
         }

         pSubsetLayout->setSpacing(10);
         pSubsetLayout->addWidget(mpSubsetPage);
      }

      QWidget* pExporterWidget = NULL;
      if (mpExporterPage != NULL)
      {
         pExporterWidget = new QWidget();
         mpExporterPage->setParent(pExporterWidget);

         QVBoxLayout* pExporterLayout = new QVBoxLayout(pExporterWidget);
         if (mpSubsetPage != NULL)
         {
            pExporterLayout->setMargin(10);
         }
         else
         {
            pExporterLayout->setMargin(0);
         }

         pExporterLayout->setSpacing(10);
         pExporterLayout->addWidget(mpExporterPage);
      }

      if ((pSubsetWidget != NULL) && (pExporterWidget != NULL))
      {
         QString strExporterCaption = mpExporterPage->windowTitle();
         if (strExporterCaption.isEmpty() == true)
         {
            PlugIn* pPlugIn = mpExporter->getPlugIn();
            if (pPlugIn != NULL)
            {
               strExporterCaption = QString::fromStdString(pPlugIn->getName());
            }

            if (strExporterCaption.isEmpty() == true)
            {
               strExporterCaption = "Exporter";
            }
         }

         mpTabWidget = new QTabWidget(this);
         mpTabWidget->setTabPosition(QTabWidget::North);
         mpTabWidget->addTab(pSubsetWidget, "Subset");
         mpTabWidget->addTab(pExporterWidget, strExporterCaption);
         pStack->addWidget(mpTabWidget);
      }
      else if (pSubsetWidget != NULL)
      {
         pStack->addWidget(pSubsetWidget);
         pButtonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
      }
      else if (pExporterWidget != NULL)
      {
         pStack->addWidget(pExporterWidget);
      }
   }

   if (pStack->count() == 0)
   {
      QLabel* pNoOptionsLabel = new QLabel("No options are available", this);
      pNoOptionsLabel->setAlignment(Qt::AlignCenter);
      pNoOptionsLabel->setMinimumSize(250, 100);

      pStack->addWidget(pNoOptionsLabel);
   }

   // Connections
   VERIFYNR(connect(pButtonBox, SIGNAL(accepted()), this, SLOT(accept())));
   VERIFYNR(connect(pButtonBox, SIGNAL(rejected()), this, SLOT(reject())));
}
bool RasterElementImporterShell::performImport() const
{
   Progress* pProgress = getProgress();
   StepResource pStep("Perform import", "app", "762EF4BB-8813-4e45-B1BD-4CD237F7C151");

   FAIL_IF(mpRasterElement == NULL, "Could not find RasterElement", return false);

   RasterDataDescriptor* pDescriptor = dynamic_cast<RasterDataDescriptor*>(
      mpRasterElement->getDataDescriptor());
   FAIL_IF(pDescriptor == NULL, "Could not find RasterDataDescriptor", return false);

   string message;

//#pragma message(__FILE__ "(" STRING(__LINE__) ") : warning : Re-evaluate this code when plug-ins " \
//   "are being loaded into the global symbol space (tclarke)")
   // This was changed from a try/catch due to a problem with the exceptions 
   // not being caught and propagating up to QApplication::notify on solaris.
   // it is believed this is due to how we load plug-ins;
   // they are loaded into a private symbol space. When this changes,
   // re-evaluate the try/catch model.
   if (pDescriptor->getProcessingLocation() == ON_DISK_READ_ONLY)
   {
      Service<SessionManager> pSessionManager;
      if (pSessionManager->isSessionLoading() == false)
      {
         RasterFileDescriptor* pOrigFileDescriptor = dynamic_cast<RasterFileDescriptor*>(pDescriptor->getFileDescriptor());
         std::vector<DimensionDescriptor> orgRows = pOrigFileDescriptor->getRows();
         std::vector<DimensionDescriptor> orgColumns = pOrigFileDescriptor->getColumns();
         std::vector<DimensionDescriptor> orgBands = pOrigFileDescriptor->getBands();

         std::vector<DimensionDescriptor>::iterator iter;
         unsigned int i = 0;
         for (iter = orgRows.begin(), i = 0; iter != orgRows.end(); ++iter, ++i)
         {
            iter->setActiveNumber(i);
         }
         for (iter = orgColumns.begin(), i = 0; iter != orgColumns.end(); ++iter, ++i)
         {
            iter->setActiveNumber(i);
         }
         for (iter = orgBands.begin(), i = 0; iter != orgBands.end(); ++iter, ++i)
         {
            iter->setActiveNumber(i);
         }
         vector<DimensionDescriptor> selectedRows = getSelectedDims(orgRows,
            pDescriptor->getRows());
         vector<DimensionDescriptor> selectedColumns = getSelectedDims(orgColumns,
            pDescriptor->getColumns());
         vector<DimensionDescriptor> selectedBands = getSelectedDims(orgBands,
            pDescriptor->getBands());

         if (!RasterUtilities::chipMetadata(mpRasterElement->getMetadata(),
            selectedRows, selectedColumns, selectedBands))
         {
            return checkAbortOrError("Could not chip metadata", pStep.get());
         }
      }

      if (createRasterPager(mpRasterElement) == false)
      {
         return checkAbortOrError("Could not create pager for RasterElement", pStep.get());
      }
   }
   else
   {
      if (mpRasterElement->createDefaultPager() == false)
      {
         return checkAbortOrError("Could not allocate resources for new RasterElement", pStep.get());
      }
      RasterDataDescriptor* pSourceDescriptor = RasterUtilities::generateUnchippedRasterDataDescriptor(mpRasterElement);
      if (pSourceDescriptor == NULL)
      {
         return checkAbortOrError("Could not get unchipped RasterDataDescriptor", pStep.get());
      }

      ModelResource<RasterElement> pSourceRaster(pSourceDescriptor);
      if (pSourceRaster.get() == NULL)
      {
         return checkAbortOrError("Could not create source RasterElement", pStep.get());
      }

      if (createRasterPager(pSourceRaster.get()) == false)
      {
         return checkAbortOrError("Could not create pager for source RasterElement", pStep.get());
      }

      if (copyData(pSourceRaster.get()) == false)
      {
         return checkAbortOrError("Could not copy data from source RasterElement", pStep.get());
      }

      double value = 0.0;
      uint64_t badValueCount = mpRasterElement->sanitizeData(value);
      if (badValueCount != 0)
      {
         if (mpProgress != NULL)
         {
            string message = StringUtilities::toDisplayString(badValueCount) + " bad value(s) found in data.\n" +
               "Bad values set to " + StringUtilities::toDisplayString(value);
            mpProgress->updateProgress(message, 100, WARNING);
         }
      }
   }

   pStep->finalize(Message::Success);
   return true;
}
void ImportOptionsDlg::setCurrentDataset(ImportDescriptor* pImportDescriptor)
{
   if (pImportDescriptor == NULL)
   {
      return;
   }

   if (pImportDescriptor == mpCurrentDataset)
   {
      return;
   }

   // Apply changes to the current data set if necessary
   bool bSuccess = true;
   if ((mpCurrentDataset != NULL) && (mEditDataDescriptorModified == true))
   {
      if (mPromptForChanges == true)
      {
         int iReturn = QMessageBox::question(this, APP_NAME, "Apply changes to data?",
            QMessageBox::Yes | QMessageBox::YesToAll | QMessageBox::No | QMessageBox::Cancel);
         if ((iReturn == QMessageBox::Yes) || (iReturn == QMessageBox::YesToAll))
         {
            bSuccess = applyChanges();
            if (iReturn == QMessageBox::YesToAll)
            {
               mPromptForChanges = false;
            }
         }
         else if (iReturn == QMessageBox::No)
         {
            // Update the validation icon for the original data descriptor
            validateDataset(mpCurrentDataset->getDataDescriptor());
         }
         else if (iReturn == QMessageBox::Cancel)
         {
            bSuccess = false;
         }
      }
      else
      {
         bSuccess = applyChanges();
      }
   }

   if (bSuccess == false)
   {
      // Select the tree widget item for the previously selected data set
      selectCurrentDatasetItem();
      return;
   }

   mpCurrentDataset = pImportDescriptor;

   // Destroy the existing edit data descriptor if necessary
   Service<ModelServices> pModel;
   if (mpEditDescriptor != NULL)
   {
      Classification* pClassification = mpEditDescriptor->getClassification();
      if (pClassification != NULL)
      {
         VERIFYNR(pClassification->detach(SIGNAL_NAME(Subject, Modified),
            Slot(this, &ImportOptionsDlg::editClassificationModified)));
      }

      RasterDataDescriptor* pRasterDescriptor = dynamic_cast<RasterDataDescriptor*>(mpEditDescriptor);
      if (pRasterDescriptor != NULL)
      {
         VERIFYNR(pRasterDescriptor->detach(SIGNAL_NAME(RasterDataDescriptor, RowsChanged),
            Slot(this, &ImportOptionsDlg::editDataDescriptorRowsModified)));
         VERIFYNR(pRasterDescriptor->detach(SIGNAL_NAME(RasterDataDescriptor, ColumnsChanged),
            Slot(this, &ImportOptionsDlg::editDataDescriptorColumnsModified)));
         VERIFYNR(pRasterDescriptor->detach(SIGNAL_NAME(RasterDataDescriptor, BandsChanged),
            Slot(this, &ImportOptionsDlg::editDataDescriptorBandsModified)));
      }

      RasterFileDescriptor* pRasterFileDescriptor =
         dynamic_cast<RasterFileDescriptor*>(mpEditDescriptor->getFileDescriptor());
      if (pRasterFileDescriptor != NULL)
      {
         VERIFYNR(pRasterFileDescriptor->detach(SIGNAL_NAME(RasterFileDescriptor, RowsChanged),
            Slot(this, &ImportOptionsDlg::editFileDescriptorRowsModified)));
         VERIFYNR(pRasterFileDescriptor->detach(SIGNAL_NAME(RasterFileDescriptor, ColumnsChanged),
            Slot(this, &ImportOptionsDlg::editFileDescriptorColumnsModified)));
         VERIFYNR(pRasterFileDescriptor->detach(SIGNAL_NAME(RasterFileDescriptor, BandsChanged),
            Slot(this, &ImportOptionsDlg::editFileDescriptorBandsModified)));
      }

      VERIFYNR(mpEditDescriptor->detach(SIGNAL_NAME(Subject, Modified),
         Slot(this, &ImportOptionsDlg::editDataDescriptorModified)));
      pModel->destroyDataDescriptor(mpEditDescriptor);
      mpEditDescriptor = NULL;
      mEditDataDescriptorModified = false;
   }

   // Create a new data descriptor to validate the user inputs
   DataDescriptor* pDescriptor = mpCurrentDataset->getDataDescriptor();
   if (pDescriptor != NULL)
   {
      mpEditDescriptor = pDescriptor->copy();
   }

   VERIFYNRV(mpEditDescriptor != NULL);
   VERIFYNR(mpEditDescriptor->attach(SIGNAL_NAME(Subject, Modified),
      Slot(this, &ImportOptionsDlg::editDataDescriptorModified)));

   RasterDataDescriptor* pRasterDescriptor = dynamic_cast<RasterDataDescriptor*>(mpEditDescriptor);
   FileDescriptor* pFileDescriptor = mpEditDescriptor->getFileDescriptor();
   RasterFileDescriptor* pRasterFileDescriptor = dynamic_cast<RasterFileDescriptor*>(pFileDescriptor);

   if (pRasterDescriptor != NULL)
   {
      VERIFYNR(pRasterDescriptor->attach(SIGNAL_NAME(RasterDataDescriptor, RowsChanged),
         Slot(this, &ImportOptionsDlg::editDataDescriptorRowsModified)));
      VERIFYNR(pRasterDescriptor->attach(SIGNAL_NAME(RasterDataDescriptor, ColumnsChanged),
         Slot(this, &ImportOptionsDlg::editDataDescriptorColumnsModified)));
      VERIFYNR(pRasterDescriptor->attach(SIGNAL_NAME(RasterDataDescriptor, BandsChanged),
         Slot(this, &ImportOptionsDlg::editDataDescriptorBandsModified)));
   }

   if (pRasterFileDescriptor != NULL)
   {
      VERIFYNR(pRasterFileDescriptor->attach(SIGNAL_NAME(RasterFileDescriptor, RowsChanged),
         Slot(this, &ImportOptionsDlg::editFileDescriptorRowsModified)));
      VERIFYNR(pRasterFileDescriptor->attach(SIGNAL_NAME(RasterFileDescriptor, ColumnsChanged),
         Slot(this, &ImportOptionsDlg::editFileDescriptorColumnsModified)));
      VERIFYNR(pRasterFileDescriptor->attach(SIGNAL_NAME(RasterFileDescriptor, BandsChanged),
         Slot(this, &ImportOptionsDlg::editFileDescriptorBandsModified)));
   }

   // Select the tree widget item for the current data set
   selectCurrentDatasetItem();

   // Disconnect pages
   updateConnections(false);

   // Subset page
   if (pRasterFileDescriptor != NULL)
   {
      // Show the tab if necessary
      if (mpTabWidget->indexOf(mpSubsetPage) == -1)
      {
         mpTabWidget->insertTab(2, mpSubsetPage, "Subset");
      }

      // Rows
      const vector<DimensionDescriptor>& rows = pRasterFileDescriptor->getRows();
      const vector<DimensionDescriptor>& loadedRows = pRasterDescriptor->getRows();
      mpSubsetPage->setRows(rows, loadedRows);

      // Columns
      const vector<DimensionDescriptor>& columns = pRasterFileDescriptor->getColumns();
      const vector<DimensionDescriptor>& loadedColumns = pRasterDescriptor->getColumns();
      mpSubsetPage->setColumns(columns, loadedColumns);

      // Bands
      const vector<DimensionDescriptor>& bands = pRasterFileDescriptor->getBands();
      const vector<DimensionDescriptor>& selectedBands = pRasterDescriptor->getBands();
      setSubsetBands(bands, selectedBands);

      // Initial bad band file directory
      if (pFileDescriptor != NULL)
      {
         QString strDirectory;

         string filename = pFileDescriptor->getFilename();
         if (filename.empty() == false)
         {
            QFileInfo fileInfo(QString::fromStdString(filename));
            strDirectory = fileInfo.absolutePath();
         }

         mpSubsetPage->setBadBandFileDirectory(strDirectory);
      }
   }
   else
   {
      // Remove the subset page, since the file descriptor either isn't
      // present or isn't a RasterFileDescriptor, just a FileDescriptor
      int index = mpTabWidget->indexOf(mpSubsetPage);
      if (index != -1)
      {
         mpTabWidget->removeTab(index);
      }
   }

   // Data descriptor page - enable editing for all fields
   mpDataPage->setDataDescriptor(mpEditDescriptor, true);

   // File descriptor page
   bool editFilePage = false;
   if (pRasterFileDescriptor != NULL)
   {
      unsigned int numRows = pRasterFileDescriptor->getRowCount();
      unsigned int numColumns = pRasterFileDescriptor->getColumnCount();
      unsigned int bitsPerElement = pRasterFileDescriptor->getBitsPerElement();
      unsigned int numBands = pRasterFileDescriptor->getBandCount();
      if ((numRows == 0) || (numColumns == 0) || (numBands == 0) || (bitsPerElement == 0))
      {
         editFilePage = true;
      }
   }

   mpFilePage->setFileDescriptor(pFileDescriptor, editFilePage);

   int iIndex = mpTabWidget->indexOf(mpFilePage);
   if (iIndex != -1)
   {
      if (pFileDescriptor == NULL)
      {
         mpTabWidget->removeTab(iIndex);
      }
   }
   else
   {
      if (pFileDescriptor != NULL)
      {
         mpTabWidget->insertTab(1, mpFilePage, "File");
      }
   }

   // Classification page
   updateClassificationLabel();

   Classification* pClassification = mpEditDescriptor->getClassification();
   if (pClassification != NULL)
   {
      VERIFYNR(pClassification->attach(SIGNAL_NAME(Subject, Modified),
         Slot(this, &ImportOptionsDlg::editClassificationModified)));
      mpClassificationPage->setClassification(pClassification);
   }

   // Metadata page
   mpMetadataPage->setMetadata(mpEditDescriptor->getMetadata());

   // Wavelengths page
   bool bWavelengthsPageActive = false;
   if (mpTabWidget->currentWidget() == mpWavelengthsPage)
   {
      bWavelengthsPageActive = true;
   }

   int index = mpTabWidget->indexOf(mpWavelengthsPage);
   if (index != -1)
   {
      mpTabWidget->removeTab(index);
   }

   if (pRasterFileDescriptor != NULL)
   {
      // Populate the wavelengths with the file descriptor bands since the metadata wavelengths
      // apply to all bands in the file
      mpWavelengthsPage->setWavelengths(pRasterFileDescriptor->getBands(), mpEditDescriptor->getMetadata());

      if (pRasterDescriptor != NULL)
      {
         mpWavelengthsPage->highlightActiveBands(pRasterDescriptor->getBands());
      }

      mpTabWidget->addTab(mpWavelengthsPage, "Wavelengths");

      if (bWavelengthsPageActive == true)
      {
         mpTabWidget->setCurrentWidget(mpWavelengthsPage);
      }
   }

   // Importer page
   bool bImporterPageActive = false;
   if (mpImporterPage != NULL)
   {
      if (mpTabWidget->currentWidget() == mpImporterPage)
      {
         bImporterPageActive = true;
      }
   }

   removeImporterPage();

   if (mpImporter != NULL)
   {
      mpImporterPage = mpImporter->getImportOptionsWidget(mpEditDescriptor);
      if (mpImporterPage != NULL)
      {
         QLayout* pLayout = mpImporterPage->layout();
         if (pLayout != NULL)
         {
            if (pLayout->margin() <= 0)
            {
               pLayout->setMargin(10);
            }
         }

         QString strCaption = mpImporterPage->windowTitle();
         if (strCaption.isEmpty() == true)
         {
            strCaption = "Importer";
         }

         mpTabWidget->addTab(mpImporterPage, strCaption);

         if (bImporterPageActive == true)
         {
            mpTabWidget->setCurrentWidget(mpImporterPage);
         }
      }

      // Set the valid processing locations on the data page.  This must be done after getting the import options
      // widget from the importer so that the auto importer will correctly query the importer that is used.
      // This can be changed if the importer design (and auto importer) is modified to support valid processing
      // locations for a specific data set.
      vector<ProcessingLocation> locations;
      if (mpImporter->isProcessingLocationSupported(IN_MEMORY) == true)
      {
         locations.push_back(IN_MEMORY);
      }

      if (mpImporter->isProcessingLocationSupported(ON_DISK) == true)
      {
         locations.push_back(ON_DISK);
      }

      if (mpImporter->isProcessingLocationSupported(ON_DISK_READ_ONLY) == true)
      {
         locations.push_back(ON_DISK_READ_ONLY);
      }

      mpDataPage->setValidProcessingLocations(locations);
   }

   // Validate the current data descriptor
   validateEditDataset();

   // Reconnect the pages
   updateConnections(true);

   // Notify connected objects
   emit currentDatasetChanged(mpCurrentDataset);
}
TreExportStatus Nitf::BandsaParser::exportMetadata(const RasterDataDescriptor &descriptor, 
   const RasterFileDescriptor &exportDescriptor, DynamicObject &tre, 
   unsigned int & ownerIndex, string & tagType, string &errorMessage) const
{
   // Find out if we are exporting a subset of the original bands. If so then delete the
   // band info for the excluded bands.

   const DynamicObject* pMetadata = descriptor.getMetadata();
   VERIFYRV(pMetadata != NULL, REMOVE);
   try
   {
      const DataVariant& nitfMetadata = pMetadata->getAttribute(Nitf::NITF_METADATA);
      const DynamicObject* pExistingBandsa = getTagHandle(dv_cast<DynamicObject>(nitfMetadata), "BANDSA", FindFirst());
      if (!pExistingBandsa)
      {
         return UNCHANGED;
      }

      const vector<DimensionDescriptor>& exportBands = exportDescriptor.getBands();

      VERIFYRV(!exportBands.empty(), REMOVE);

      tre.setAttribute(Nitf::TRE::BANDSA::ROW_SPACING,
         pExistingBandsa->getAttribute(Nitf::TRE::BANDSA::ROW_SPACING));
      tre.setAttribute(Nitf::TRE::BANDSA::ROW_SPACING_UNITS,
         pExistingBandsa->getAttribute(Nitf::TRE::BANDSA::ROW_SPACING_UNITS));
      tre.setAttribute(Nitf::TRE::BANDSA::COL_SPACING,
         pExistingBandsa->getAttribute(Nitf::TRE::BANDSA::COL_SPACING));
      tre.setAttribute(Nitf::TRE::BANDSA::COL_SPACING_UNITS,
         pExistingBandsa->getAttribute(Nitf::TRE::BANDSA::COL_SPACING_UNITS));
      tre.setAttribute(Nitf::TRE::BANDSA::FOCAL_LENGTH,
         pExistingBandsa->getAttribute(Nitf::TRE::BANDSA::FOCAL_LENGTH));

      unsigned int bandcount(0);

      for (vector<DimensionDescriptor>::const_iterator iter = exportBands.begin(); iter != exportBands.end(); ++iter)
      {
         // Use the original band number to find the associated band data in the original TRE
         LOG_IF(!iter->isOriginalNumberValid(), continue);
         unsigned int origBandNum = iter->getOriginalNumber();

         stringstream bandStreamStr;
         bandStreamStr << "#" << bandcount;
         string bandStr(bandStreamStr.str());

         stringstream origBandStreamStr;
         origBandStreamStr << "#" << origBandNum;
         string origBandStr(origBandStreamStr.str());

         ++bandcount;

         string fieldName;
         string origFieldName;

         fieldName = BANDSA::BANDPEAK + bandStr;
         origFieldName = BANDSA::BANDPEAK + origBandStr;
         tre.setAttribute(fieldName, pExistingBandsa->getAttribute(origFieldName));

         fieldName = BANDSA::BANDLBOUND + bandStr;
         origFieldName = BANDSA::BANDLBOUND + origBandStr;
         tre.setAttribute(fieldName, pExistingBandsa->getAttribute(origFieldName));

         fieldName = BANDSA::BANDUBOUND + bandStr;
         origFieldName = BANDSA::BANDUBOUND + origBandStr;
         tre.setAttribute(fieldName, pExistingBandsa->getAttribute(origFieldName));

         fieldName = BANDSA::BANDWIDTH + bandStr;
         origFieldName = BANDSA::BANDWIDTH + origBandStr;
         tre.setAttribute(fieldName, pExistingBandsa->getAttribute(origFieldName));

         fieldName = BANDSA::BANDCALDRK + bandStr;
         origFieldName = BANDSA::BANDCALDRK + origBandStr;
         tre.setAttribute(fieldName, pExistingBandsa->getAttribute(origFieldName));

         fieldName = BANDSA::BANDCALINC + bandStr;
         origFieldName = BANDSA::BANDCALINC + origBandStr;
         tre.setAttribute(fieldName, pExistingBandsa->getAttribute(origFieldName));

         fieldName = BANDSA::BANDRESP + bandStr;
         origFieldName = BANDSA::BANDRESP + origBandStr;
         tre.setAttribute(fieldName, pExistingBandsa->getAttribute(origFieldName));

         fieldName = BANDSA::BANDASD + bandStr;
         origFieldName = BANDSA::BANDASD + origBandStr;
         tre.setAttribute(fieldName, pExistingBandsa->getAttribute(origFieldName));

         fieldName = BANDSA::BANDGSD + bandStr;
         origFieldName = BANDSA::BANDGSD + origBandStr;
         tre.setAttribute(fieldName, pExistingBandsa->getAttribute(origFieldName));
      }

      tre.setAttribute(Nitf::TRE::BANDSA::BANDCOUNT, bandcount);
   }
   catch (const bad_cast&)
   {
      return REMOVE;
   }
   catch (const string& message)
   {
      errorMessage = message;
      return REMOVE;
   }

   return REPLACE;
}
bool EditDataDescriptor::execute(PlugInArgList* pInArgList, PlugInArgList* pOutArgList)
{
   StepResource pStep("Execute Wizard Item", "app", "055486F4-A9DB-4FDA-9AA7-75D1917E2C87");
   pStep->addProperty("Item", getName());
   mpStep = pStep.get();

   if (extractInputArgs(pInArgList) == false)
   {
      return false;
   }

   // Set the values in the data descriptor
   VERIFY(mpDescriptor != NULL);

   // File descriptor
   if (mpFileDescriptor != NULL)
   {
      mpDescriptor->setFileDescriptor(mpFileDescriptor);
   }

   // Processing location
   if (mpProcessingLocation != NULL)
   {
      mpDescriptor->setProcessingLocation(*mpProcessingLocation);
   }

   RasterDataDescriptor* pRasterDescriptor = dynamic_cast<RasterDataDescriptor*>(mpDescriptor);
   RasterFileDescriptor* pRasterFileDescriptor = dynamic_cast<RasterFileDescriptor*>(mpFileDescriptor);
   SignatureDataDescriptor* pSignatureDescriptor = dynamic_cast<SignatureDataDescriptor*>(mpDescriptor);
   SignatureFileDescriptor* pSignatureFileDescriptor = dynamic_cast<SignatureFileDescriptor*>(mpFileDescriptor);

   if (pRasterDescriptor != NULL)
   {
      if (pRasterFileDescriptor != NULL)
      {
         // Set the rows and columns to match the rows and columns in the file descriptor before creating the subset
         const vector<DimensionDescriptor>& rows = pRasterFileDescriptor->getRows();
         pRasterDescriptor->setRows(rows);

         const vector<DimensionDescriptor>& columns = pRasterFileDescriptor->getColumns();
         pRasterDescriptor->setColumns(columns);

         const vector<DimensionDescriptor>& bands = pRasterFileDescriptor->getBands();
         pRasterDescriptor->setBands(bands);
      }

      // Data type
      if (mpDataType != NULL)
      {
         pRasterDescriptor->setDataType(*mpDataType);
      }

      // InterleaveFormat
      if (mpInterleave != NULL)
      {
         pRasterDescriptor->setInterleaveFormat(*mpInterleave);
      }

      // Bad values
      if (mpBadValues != NULL)
      {
         pRasterDescriptor->setBadValues(*mpBadValues);
      }

      // Rows
      if ((mpStartRow != NULL) || (mpEndRow != NULL) || (mpRowSkipFactor != NULL))
      {
         // We need to obtain this origRows from the FileDescriptor if present since an importer
         // may generate a subset by default in which case the DataDescriptor will not contain all
         // the rows and subsetting will not work correctly. We
         // can't just set mpFileDescriptor = pRasterDescriptor->getFileDescriptor() since we only
         // want to replace the DataDescriptor's row list if one of the subset options is specified
         const RasterFileDescriptor* pFileDesc(pRasterFileDescriptor);
         if (pFileDesc == NULL)
         {
            pFileDesc = dynamic_cast<const RasterFileDescriptor*>(pRasterDescriptor->getFileDescriptor());
         }
         const vector<DimensionDescriptor>& origRows = (pFileDesc != NULL) ?
            pFileDesc->getRows() : pRasterDescriptor->getRows();
         unsigned int startRow = 0;
         if (mpStartRow != NULL)
         {
            startRow = *mpStartRow;
         }
         else if (origRows.empty() == false)
         {
            startRow = origRows.front().getOriginalNumber() + 1;
         }

         unsigned int endRow = 0;
         if (mpEndRow != NULL)
         {
            endRow = *mpEndRow;
         }
         else if (origRows.empty() == false)
         {
            endRow = origRows.back().getOriginalNumber() + 1;
         }

         unsigned int rowSkip = 0;
         if (mpRowSkipFactor != NULL)
         {
            rowSkip = *mpRowSkipFactor;
         }

         vector<DimensionDescriptor> rows;
         for (unsigned int i = 0; i < origRows.size(); ++i)
         {
            DimensionDescriptor rowDim = origRows[i];
            unsigned int originalNumber = rowDim.getOriginalNumber() + 1;
            if ((originalNumber >= startRow) && (originalNumber <= endRow))
            {
               rows.push_back(rowDim);
               i += rowSkip;
            }
         }

         pRasterDescriptor->setRows(rows);
      }

      // Columns
      if ((mpStartColumn != NULL) || (mpEndColumn != NULL) || (mpColumnSkipFactor != NULL))
      {
         // We need to obtain this origColumns from the FileDescriptor if present since an importer
         // may generate a subset by default in which case the DataDescriptor will not contain all
         // the columns and subsetting will not work correctly. We
         // can't just set mpFileDescriptor = pRasterDescriptor->getFileDescriptor() since we only
         // want to replace the DataDescriptor's column list if one of the subset options is specified
         const RasterFileDescriptor* pFileDesc(pRasterFileDescriptor);
         if (pFileDesc == NULL)
         {
            pFileDesc = dynamic_cast<const RasterFileDescriptor*>(pRasterDescriptor->getFileDescriptor());
         }
         const vector<DimensionDescriptor>& origColumns = (pFileDesc != NULL) ?
            pFileDesc->getColumns() : pRasterDescriptor->getColumns();

         unsigned int startColumn = 0;
         if (mpStartColumn != NULL)
         {
            startColumn = *mpStartColumn;
         }
         else if (origColumns.empty() == false)
         {
            startColumn = origColumns.front().getOriginalNumber() + 1;
         }

         unsigned int endColumn = 0;
         if (mpEndColumn != NULL)
         {
            endColumn = *mpEndColumn;
         }
         else if (origColumns.empty() == false)
         {
            endColumn = origColumns.back().getOriginalNumber() + 1;
         }

         unsigned int columnSkip = 0;
         if (mpColumnSkipFactor != NULL)
         {
            columnSkip = *mpColumnSkipFactor;
         }

         vector<DimensionDescriptor> columns;
         for (unsigned int i = 0; i < origColumns.size(); ++i)
         {
            DimensionDescriptor columnDim = origColumns[i];
            unsigned int originalNumber = columnDim.getOriginalNumber() + 1;
            if ((originalNumber >= startColumn) && (originalNumber <= endColumn))
            {
               columns.push_back(columnDim);
               i += columnSkip;
            }
         }

         pRasterDescriptor->setColumns(columns);
      }

      // Bands
      if ((mpStartBand != NULL) || (mpEndBand != NULL) || (mpBandSkipFactor != NULL) || (mpBadBandsFile != NULL))
      {
         // We need to obtain this origBands from the FileDescriptor if present since an importer
         // may generate a subset by default in which case the DataDescriptor will not contain all
         // the bands and subsetting (especially by bad band file) will not work correctly. We
         // can't just set mpFileDescriptor = pRasterDescriptor->getFileDescriptor() since we only
         // want to replace the DataDescriptor's band list if one of the subset options is specified
         const RasterFileDescriptor* pFileDesc(pRasterFileDescriptor);
         if (pFileDesc == NULL)
         {
            pFileDesc = dynamic_cast<const RasterFileDescriptor*>(pRasterDescriptor->getFileDescriptor());
         }
         const vector<DimensionDescriptor>& origBands = (pFileDesc != NULL) ?
            pFileDesc->getBands() : pRasterDescriptor->getBands();

         unsigned int startBand = 0;
         if (mpStartBand != NULL)
         {
            startBand = *mpStartBand;
         }
         else if (origBands.empty() == false)
         {
            startBand = origBands.front().getOriginalNumber() + 1;
         }

         unsigned int endBand = 0;
         if (mpEndBand != NULL)
         {
            endBand = *mpEndBand;
         }
         else if (origBands.empty() == false)
         {
            endBand = origBands.back().getOriginalNumber() + 1;
         }

         unsigned int bandSkip = 0;
         if (mpBandSkipFactor != NULL)
         {
            bandSkip = *mpBandSkipFactor;
         }

         // Get the bad bands from the file
         vector<unsigned int> badBands;
         if (mpBadBandsFile != NULL)
         {
            string filename = *mpBadBandsFile;
            if (filename.empty() == false)
            {
               FILE* pFile = fopen(filename.c_str(), "rb");
               if (pFile != NULL)
               {
                  char line[1024];
                  while (fgets(line, 1024, pFile) != NULL)
                  {
                     unsigned int bandNumber = 0;

                     int iValues = sscanf(line, "%u", &bandNumber);
                     if (iValues == 1)
                     {
                        badBands.push_back(bandNumber);
                     }
                  }

                  fclose(pFile);
               }
            }
         }

         vector<DimensionDescriptor> bands;
         for (unsigned int i = 0; i < origBands.size(); ++i)
         {
            DimensionDescriptor bandDim = origBands[i];
            unsigned int originalNumber = bandDim.getOriginalNumber() + 1;
            if ((originalNumber >= startBand) && (originalNumber <= endBand))
            {
               bool bBad = false;
               for (unsigned int j = 0; j < badBands.size(); ++j)
               {
                  unsigned int badBandNumber = badBands[j];
                  if (originalNumber == badBandNumber)
                  {
                     bBad = true;
                     break;
                  }
               }

               if (bBad == false)
               {
                  bands.push_back(bandDim);
                  i += bandSkip;
               }
            }
         }

         pRasterDescriptor->setBands(bands);
      }

      // X pixel size
      if (mpPixelSizeX != NULL)
      {
         pRasterDescriptor->setXPixelSize(*mpPixelSizeX);
      }

      // Y pixel size
      if (mpPixelSizeY != NULL)
      {
         pRasterDescriptor->setYPixelSize(*mpPixelSizeY);
      }

      // Units
      if ((mpUnitsName != NULL) || (mpUnitsType != NULL) ||
         (mpUnitsScale != NULL) || (mpUnitsRangeMin != NULL) || (mpUnitsRangeMax != NULL))
      {
         const Units* pOrigUnits = pRasterDescriptor->getUnits();

         FactoryResource<Units> pUnits;
         VERIFY(pUnits.get() != NULL);

         // Name
         if (mpUnitsName != NULL)
         {
            pUnits->setUnitName(*mpUnitsName);
         }
         else if (pOrigUnits != NULL)
         {
            pUnits->setUnitName(pOrigUnits->getUnitName());
         }

         // Type
         if (mpUnitsType != NULL)
         {
            pUnits->setUnitType(*mpUnitsType);
         }
         else if (pOrigUnits != NULL)
         {
            pUnits->setUnitType(pOrigUnits->getUnitType());
         }

         // Scale
         if (mpUnitsScale != NULL)
         {
            pUnits->setScaleFromStandard(*mpUnitsScale);
         }
         else if (pOrigUnits != NULL)
         {
            pUnits->setScaleFromStandard(pOrigUnits->getScaleFromStandard());
         }

         // Range minimum
         if (mpUnitsRangeMin != NULL)
         {
            pUnits->setRangeMin(*mpUnitsRangeMin);
         }
         else if (pOrigUnits != NULL)
         {
            pUnits->setRangeMin(pOrigUnits->getRangeMin());
         }

         // Range maximum
         if (mpUnitsRangeMax != NULL)
         {
            pUnits->setRangeMax(*mpUnitsRangeMax);
         }
         else if (pOrigUnits != NULL)
         {
            pUnits->setRangeMax(pOrigUnits->getRangeMax());
         }

         pRasterDescriptor->setUnits(pUnits.get());
      }

      // Display mode
      if (mpDisplayMode != NULL)
      {
         pRasterDescriptor->setDisplayMode(*mpDisplayMode);
      }

      // Display bands
      // Gray
      if (mpGrayBand != NULL)
      {
         DimensionDescriptor band = pRasterDescriptor->getOriginalBand(*mpGrayBand - 1);
         pRasterDescriptor->setDisplayBand(GRAY, band);
      }

      // Red
      if (mpRedBand != NULL)
      {
         DimensionDescriptor band = pRasterDescriptor->getOriginalBand(*mpRedBand - 1);
         pRasterDescriptor->setDisplayBand(RED, band);
      }

      // Green
      if (mpGreenBand != NULL)
      {
         DimensionDescriptor band = pRasterDescriptor->getOriginalBand(*mpGreenBand - 1);
         pRasterDescriptor->setDisplayBand(GREEN, band);
      }

      // Blue
      if (mpBlueBand != NULL)
      {
         DimensionDescriptor band = pRasterDescriptor->getOriginalBand(*mpBlueBand - 1);
         pRasterDescriptor->setDisplayBand(BLUE, band);
      }
   }
   else if (pSignatureDescriptor != NULL)
   {
      if (mpComponentName != NULL)
      {
         const Units* pOrigUnits = pSignatureDescriptor->getUnits(*mpComponentName);
         FactoryResource<Units> pUnits;
         if (pOrigUnits != NULL)
         {
            *pUnits = *pOrigUnits;
         }
         if (mpUnitsName != NULL)
         {
            pUnits->setUnitName(*mpUnitsName);
         }
         if (mpUnitsType != NULL)
         {
            pUnits->setUnitType(*mpUnitsType);
         }
         if (mpUnitsScale != NULL)
         {
            pUnits->setScaleFromStandard(*mpUnitsScale);
         }
         if (mpUnitsRangeMin != NULL)
         {
            pUnits->setRangeMin(*mpUnitsRangeMin);
         }
         if (mpUnitsRangeMax != NULL)
         {
            pUnits->setRangeMax(*mpUnitsRangeMax);
         }
         pSignatureDescriptor->setUnits(*mpComponentName, pUnits.get());
      }
   }

   reportComplete();
   return true;
}