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
19using std::stringstream;
20
21namespace 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
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}
Isis exception class.
Definition IException.h:91
This widget encompasses the entire mosaic scene.
void applySettings()
Take the settings that have been configured and apply them to the mosaic scene.
void saveToFile()
Save mapping parameters to the given file.
ProjectionConfigDialog(MosaicSceneWidget *scene, QWidget *parent=NULL)
Create a projection configuration dialog.
void beginQuickLoad()
If using quick load, this will prompt the user for an input file right after the show event.
void showErrors(int)
This is called when "Show Errors" is checked.
bool m_dirty
To reduce redundant computations, keep track of dirty state of the dialog.
QPointer< QTextEdit > m_mapFileEdit
This is the text area that a user can type in for editing the projection.
QPointer< MosaicSceneWidget > m_scene
The mosaic scene we're configuring the projection for.
Projection * createProjection()
Convert the current text in the text edit to a projection.
bool m_quick
Should we minimize the user interaction?
QPointer< QPushButton > m_okayButton
This button applies the current projection to the scene and closes the dialog.
QPointer< QLabel > m_errorsLabel
This shows errors generated by trying to create a projection from the current mapping pvl.
Pvl addMissingKeywords(Pvl mappingPvl)
Get a modified mapping pvl that the mosaic scene will be compatible with.
void setQuickConfig(bool quick)
Enable/disable minimal interaction mode.
void refreshWidgetStates()
Update the enabled/disabled states of the various widgets based on the current user inputs' states.
QPointer< QPushButton > m_readFromFileButton
This button corresponds to 'Load Map File...' and causes a prompt for file input.
QPointer< QLabel > m_stateLabel
This shows a general idea of the current state of the mapping pvl (always shown)
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.
void readSettings()
Update the current widgets' states with the current settings in the mosaic scene.
static Isis::Projection * Create(Isis::Pvl &label, bool allowDefaults=false)
This method returns a pointer to a Projection object.
Base class for Map Projections.
Definition Projection.h:155
Contains multiple PvlContainers.
Definition PvlGroup.h:41
Container for cube-like labels.
Definition Pvl.h:119
A single keyword-value pair.
Definition PvlKeyword.h:87
@ Traverse
Search child objects.
Definition PvlObject.h:158
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16