Isis 3 Programmer Reference
ProjectionConfigDialog.cpp
1 #include "ProjectionConfigDialog.h"
2 
3 #include <sstream>
4 
5 #include <QCheckBox>
6 #include <QFileDialog>
7 #include <QGridLayout>
8 #include <QLabel>
9 #include <QMessageBox>
10 #include <QPushButton>
11 #include <QTextEdit>
12 
13 #include "IException.h"
14 #include "MosaicSceneWidget.h"
15 #include "Projection.h"
16 #include "ProjectionFactory.h"
17 #include "Pvl.h"
18 
19 using std::stringstream;
20 
21 namespace Isis {
30  QDialog(parent) {
31  m_scene = scene;
32  m_dirty = false;
33  m_quick = false;
34 
35  QGridLayout *mainLayout = new QGridLayout;
36 
37  /*
38  * The layout is shown below:
39  *
40  * |--------------------------------------------------------------|
41  * | Header |
42  * |--------------------------------------------------------------|
43  * | Description |
44  * |--------------------------------------------------------------|
45  * | Load From File... Save To File... |
46  * |--------------------------------------------------------------|
47  * | Text Edit |
48  * |--------------------------------------------------------------|
49  * | Errors |
50  * |--------------------------------------------------------------|
51  * | Show Errors Ok Apply Cancel |
52  * |--------------------------------------------------------------|
53  */
54 
55  int row = 0;
56  QLabel *headerLabel = new QLabel("<h3>Configure Projection/Mapping Parameters</h3>");
57  mainLayout->addWidget(headerLabel, row, 0);
58  row++;
59 
60  QLabel *descriptionLabel = new QLabel("The projection determines how the footprints will be "
61  "shown on the scene. This projection will be used to convert from latitude/longitude to "
62  "scene coordinates (x, y).<br/><br/>Please keep in mind:<br/><b>Load Map File...</b> will "
63  "read all of the keywords in the mapping group from the input file (unnecessary keywords "
64  "included).<br/>"
65  "<b>Save Map File...</b> will save what's currently in the display (unnecessary keywords "
66  "included).<br/>"
67  "<b>Ok and Apply</b> will remove all unnecessary or unknown keywords immediately.<br/>");
68  descriptionLabel->setWordWrap(true);
69  mainLayout->addWidget(descriptionLabel, row, 0);
70  row++;
71 
72  QHBoxLayout *loadSaveLayout = new QHBoxLayout;
73 
74  QPushButton *saveToFile = new QPushButton("&Save Map File...");
75  connect(saveToFile, SIGNAL(clicked()),
76  this, SLOT(saveToFile()));
77  loadSaveLayout->addWidget(saveToFile);
78 
79  m_readFromFileButton = new QPushButton("&Load Map File...");
80  connect(m_readFromFileButton, SIGNAL(clicked()),
81  this, SLOT(loadFromFile()));
82  loadSaveLayout->addWidget(m_readFromFileButton);
83 
84  loadSaveLayout->addStretch();
85  mainLayout->addLayout(loadSaveLayout, row, 0);
86  row++;
87 
88  QFont font("Monospace");
89  font.setStyleHint(QFont::TypeWriter);
90 
91  m_mapFileEdit = new QTextEdit;
92  m_mapFileEdit->setFont(font);
93  connect(m_mapFileEdit, SIGNAL(textChanged()),
94  this, SLOT(refreshWidgetStates()));
95  mainLayout->addWidget(m_mapFileEdit, row, 0);
96  row++;
97 
98  m_stateLabel = new QLabel;
99  mainLayout->addWidget(m_stateLabel, row, 0);
100  row++;
101 
102  m_errorsLabel = new QLabel;
103  m_errorsLabel->setWordWrap(true);
104  mainLayout->addWidget(m_errorsLabel, row, 0);
105  row++;
106 
107  QHBoxLayout *applyButtonsLayout = new QHBoxLayout;
108 
109  QCheckBox *showErrorsCheckBox = new QCheckBox(tr("Show Errors"));
110  connect(showErrorsCheckBox, SIGNAL(stateChanged(int)),
111  this, SLOT(showErrors(int)));
112  showErrors(showErrorsCheckBox->isChecked());
113  applyButtonsLayout->addWidget(showErrorsCheckBox);
114 
115  applyButtonsLayout->addStretch();
116 
117  m_okayButton = new QPushButton("&Ok");
118  m_okayButton->setIcon(QIcon::fromTheme("dialog-ok"));
119  connect(m_okayButton, SIGNAL(clicked()),
120  this, SLOT(applySettings()));
121  connect(m_okayButton, SIGNAL(clicked()),
122  this, SLOT(accept()));
123  applyButtonsLayout->addWidget(m_okayButton);
124 
125  m_applyButton = new QPushButton("&Apply");
126  m_applyButton->setIcon(QIcon::fromTheme("dialog-ok-apply"));
127  connect(m_applyButton, SIGNAL(clicked()),
128  this, SLOT(applySettings()));
129  applyButtonsLayout->addWidget(m_applyButton);
130 
131  QPushButton *cancelButton = new QPushButton("&Cancel");
132  cancelButton->setIcon(QIcon::fromTheme("dialog-cancel"));
133  connect(cancelButton, SIGNAL(clicked()),
134  this, SLOT(reject()));
135  applyButtonsLayout->addWidget(cancelButton);
136 
137  QWidget *applyButtonsWrapper = new QWidget;
138  applyButtonsWrapper->setLayout(applyButtonsLayout);
139  mainLayout->addWidget(applyButtonsWrapper, row, 0);
140  row++;
141 
142  setLayout(mainLayout);
143 
144  readSettings();
145 
146  connect(this, SIGNAL(shown()),
147  this, SLOT(beginQuickLoad()),
148  Qt::QueuedConnection);
149  }
150 
151 
152  ProjectionConfigDialog::~ProjectionConfigDialog() {
153  m_scene = NULL;
154  }
155 
156 
165  m_quick = quick;
166  }
167 
168 
173  try {
174  if (m_scene && m_dirty) {
175  m_scene->setProjection(createProjection());
176  }
177  }
178  catch (IException &) {
179  }
180 
181  readSettings();
182  }
183 
184 
190  if (m_scene && m_scene->getProjection()) {
191  Pvl mapFilePvl;
192  mapFilePvl += m_scene->getProjection()->Mapping();
193 
194  stringstream mapFileStringStream;
195  mapFileStringStream << mapFilePvl;
196 
197  m_mapFileEdit->setText(QString::fromStdString(mapFileStringStream.str()));
198  }
199 
201 
202  m_dirty = false;
203  }
204 
205 
206 
207  void ProjectionConfigDialog::showEvent(QShowEvent *event) {
208  QDialog::showEvent(event);
209 
210  emit shown();
211  }
212 
213 
218  PvlGroup &mapping = mappingPvl.findGroup("Mapping", Pvl::Traverse);
219 
220  if(!mapping.hasKeyword("MinimumLatitude"))
221  mapping += PvlKeyword("MinimumLatitude", "-90");
222 
223  if(!mapping.hasKeyword("MaximumLatitude"))
224  mapping += PvlKeyword("MaximumLatitude", "90");
225 
226  if(!mapping.hasKeyword("MinimumLongitude")) {
227  if(mapping["LongitudeDomain"][0] == "360")
228  mapping += PvlKeyword("MinimumLongitude", "0");
229  else
230  mapping += PvlKeyword("MinimumLongitude", "-180");
231  }
232 
233  if(!mapping.hasKeyword("MaximumLongitude")) {
234  if(mapping["LongitudeDomain"][0] == "360")
235  mapping += PvlKeyword("MaximumLongitude", "360");
236  else
237  mapping += PvlKeyword("MaximumLongitude", "180");
238  }
239 
240  return mappingPvl;
241  }
242 
243 
250  stringstream mapFileStringStream;
251  mapFileStringStream.str(m_mapFileEdit->toPlainText().toStdString());
252 
253  Pvl mapFilePvl;
254  mapFileStringStream >> mapFilePvl;
255  mapFilePvl = addMissingKeywords(mapFilePvl);
256 
257  return ProjectionFactory::Create(mapFilePvl);
258  }
259 
260 
267  if (m_quick && m_readFromFileButton) {
268  m_readFromFileButton->click();
269  }
270  }
271 
272 
278  QString mapFile = QFileDialog::getOpenFileName(this, tr("Select Map File"), QString("."),
279  tr("Map Files (*.map *.pvl *.cub);;Text Files (*.txt);;All Files (*)"));
280 
281  if (!mapFile.isEmpty()) {
282  bool success = false;
283 
284  try {
285  Pvl mapFilePvl(mapFile);
286  PvlGroup &mapping = mapFilePvl.findGroup("Mapping", PvlObject::Traverse);
287 
288  Pvl trimmedMapFilePvl;
289  trimmedMapFilePvl += mapping;
290 
291  stringstream trimmedMapFileStringStream;
292  trimmedMapFileStringStream << trimmedMapFilePvl;
293  m_mapFileEdit->setText(QString::fromStdString(trimmedMapFileStringStream.str()));
294 
295  success = true;
296  }
297  catch (IException &e) {
298  QMessageBox::warning(this, tr("Failed to Load Map File"),
299  tr("Failed to load projection from the given file.\n") +
300  e.toString());
301  }
302 
303 
304  if (m_quick && m_okayButton && success) {
305  try {
306  delete createProjection();
307  m_okayButton->click();
308  close();
309  }
310  catch (IException &) {
311  }
312  }
313  }
314 
315  // After we've tried one load, quick turns off. They either completed what they wanted, or
316  // need to evaluate what this dialog is telling them and modify their input.
317  m_quick = false;
318  }
319 
320 
326  QString mapFile = QFileDialog::getSaveFileName(this, tr("Save Map File"), QString("."),
327  tr("Map Files (*.map *.pvl);;Text Files (*.txt);;All Files (*)"));
328 
329  if (!mapFile.isEmpty()) {
330  QFile outputFile(mapFile);
331 
332  if (outputFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
333  QString mapFileInfo = m_mapFileEdit->toPlainText() + "\n";
334  if (outputFile.write(mapFileInfo.toLatin1()) == -1) {
335  QMessageBox::warning(this, tr("Failed to Write Text to File"),
336  tr("Failed to write the map file to [%1] due to an I/O failure").arg(mapFile));
337  }
338  }
339  else {
340  QMessageBox::warning(this, tr("Failed to Create Output File"),
341  tr("Failed to open file [%1] for writing").arg(mapFile));
342  }
343  }
344  }
345 
346 
352  bool projectionIsGood = true;
353 
354  if (m_mapFileEdit->toPlainText().trimmed().isEmpty()) {
355  m_stateLabel->setText("<strong>Please load (or type in) a map file</strong>");
356  m_errorsLabel->setText("");
357  projectionIsGood = false;
358  }
359  else {
360  try {
361  delete createProjection();
362  m_stateLabel->setText("<strong>The currently displayed text is valid</strong>");
363  m_errorsLabel->setText("");
364  }
365  catch (IException &e) {
366  m_stateLabel->setText("<strong>The currently displayed text is not valid"
367  "</strong>");
368  m_errorsLabel->setText(
369  QString("<font color='red'>&nbsp;&nbsp;") +
370  QString(e.what()).replace("\n", "<br/>&nbsp;&nbsp;") +
371  QString("</font>"));
372  projectionIsGood = false;
373  }
374  }
375 
376  m_dirty = true;
377 
378  m_okayButton->setEnabled(projectionIsGood);
379  m_applyButton->setEnabled(projectionIsGood);
380  }
381 
382 
389  void ProjectionConfigDialog::showErrors(int shouldShowErrors) {
390  m_errorsLabel->setVisible(shouldShowErrors);
391  }
392 }
static Isis::Projection * Create(Isis::Pvl &label, bool allowDefaults=false)
This method returns a pointer to a Projection object.
Pvl addMissingKeywords(Pvl mappingPvl)
Get a modified mapping pvl that the mosaic scene will be compatible with.
const char * what() const
Returns a string representation of this exception in its current state.
Definition: IException.cpp:391
bool hasKeyword(const QString &name) const
Check to see if a keyword exists.
void beginQuickLoad()
If using quick load, this will prompt the user for an input file right after the show event...
PvlGroupIterator findGroup(const QString &name, PvlGroupIterator beg, PvlGroupIterator end)
Find a group with the specified name, within these indexes.
Definition: PvlObject.h:141
void setQuickConfig(bool quick)
Enable/disable minimal interaction mode.
This widget encompasses the entire mosaic scene.
void saveToFile()
Save mapping parameters to the given file.
void refreshWidgetStates()
Update the enabled/disabled states of the various widgets based on the current user inputs&#39; states...
ProjectionConfigDialog(MosaicSceneWidget *scene, QWidget *parent=NULL)
Create a projection configuration dialog.
QPointer< QTextEdit > m_mapFileEdit
This is the text area that a user can type in for editing the projection.
void readSettings()
Update the current widgets&#39; states with the current settings in the mosaic scene. ...
Search child objects.
Definition: PvlObject.h:170
void applySettings()
Take the settings that have been configured and apply them to the mosaic scene.
QPointer< QLabel > m_stateLabel
This shows a general idea of the current state of the mapping pvl (always shown)
QPointer< MosaicSceneWidget > m_scene
The mosaic scene we&#39;re configuring the projection for.
void showErrors(int)
This is called when "Show Errors" is checked.
Base class for Map Projections.
Definition: Projection.h:171
bool m_quick
Should we minimize the user interaction?
Contains multiple PvlContainers.
Definition: PvlGroup.h:57
QPointer< QPushButton > m_readFromFileButton
This button corresponds to &#39;Load Map File...&#39; and causes a prompt for file input. ...
A single keyword-value pair.
Definition: PvlKeyword.h:98
Projection * createProjection()
Convert the current text in the text edit to a projection.
Container for cube-like labels.
Definition: Pvl.h:135
QPointer< QLabel > m_errorsLabel
This shows errors generated by trying to create a projection from the current mapping pvl...
QString toString() const
Returns a string representation of this exception.
Definition: IException.cpp:553
Isis exception class.
Definition: IException.h:107
Namespace for ISIS/Bullet specific routines.
Definition: Apollo.h:31
bool m_dirty
To reduce redundant computations, keep track of dirty state of the dialog.
QPointer< QPushButton > m_okayButton
This button applies the current projection to the scene and closes the dialog.
void loadFromFile()
Read mapping parameters from a file (prompts user for the file name).
QPointer< QPushButton > m_applyButton
This button applies the current projection to the scene.