USGS

Isis 3.0 Object Programmers' Reference

Home

MosaicSceneWidget.cpp
1 #include "IsisDebug.h"
2 
3 #include "MosaicSceneWidget.h"
4 
5 #include <sstream>
6 
7 #include <QtCore>
8 #include <QtGui>
9 #include <QtXml>
10 
11 #include "Camera.h"
12 #include "Cube.h"
13 #include "Directory.h"
14 #include "Distance.h"
15 #include "FileName.h"
16 #include "GraphicsView.h"
17 #include "Image.h"
18 #include "ImageList.h"
19 #include "Latitude.h"
20 #include "Longitude.h"
21 #include "MosaicAreaTool.h"
22 #include "MosaicControlNetTool.h"
23 #include "MosaicFindTool.h"
24 #include "MosaicGraphicsScene.h"
25 #include "MosaicGraphicsView.h"
26 #include "MosaicGridTool.h"
27 #include "MosaicPanTool.h"
28 #include "MosaicSceneItem.h"
29 #include "MosaicSelectTool.h"
30 #include "MosaicTrackTool.h"
31 #include "MosaicZoomTool.h"
32 #include "MoveDownOneSceneWorkOrder.h"
33 #include "MoveToBottomSceneWorkOrder.h"
34 #include "MoveToTopSceneWorkOrder.h"
35 #include "MoveUpOneSceneWorkOrder.h"
36 #include "ProgressBar.h"
37 #include "Project.h"
38 #include "Projection.h"
39 #include "ProjectionConfigDialog.h"
40 #include "ProjectionFactory.h"
41 #include "PvlObject.h"
42 #include "Pvl.h"
43 #include "TextFile.h"
44 #include "Target.h"
45 #include "ToolPad.h"
46 #include "TProjection.h"
47 #include "XmlStackedHandlerReader.h"
48 
49 namespace Isis {
53  MosaicSceneWidget::MosaicSceneWidget(QStatusBar *status, bool showTools,
54  bool internalizeToolBarsAndProgress, Directory *directory,
55  QWidget *parent) : QWidget(parent) {
56  m_projectImageZOrders = NULL;
57  m_projectViewTransform = NULL;
58  m_directory = directory;
59 
60  m_mosaicSceneItems = new QList<MosaicSceneItem *>;
61 
63  m_graphicsScene->installEventFilter(this);
64 
67  m_graphicsView->setInteractive(true);
68 // m_graphicsView->setViewportUpdateMode(QGraphicsView::MinimalViewportUpdate);
69  m_graphicsView->setResizeAnchor(QGraphicsView::AnchorViewCenter);
70  // This enables OpenGL acceleration
71 // m_graphicsView->setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers)));
72 // QPixmapCache::setCacheLimit(1024 * 1024);
73 
74  m_projection = NULL;
75  m_mapButton = NULL;
76  m_quickMapAction = NULL;
77 
78  m_cubesSelectable = true;
79  m_customRubberBandEnabled = false;
80  m_customRubberBand = NULL;
81  m_rubberBandOrigin = NULL;
82  m_outlineRect = NULL;
83  m_blockingSelectionChanged = false;
84  m_queuedSelectionChanged = false;
85  m_shouldRequeueSelectionChanged = false;
86 
87  m_userToolControl = false;
88  m_ownProjection = false;
89 
90  m_progress = new ProgressBar;
91  m_progress->setVisible(false);
92 
93  QGridLayout * sceneLayout = new QGridLayout;
94  sceneLayout->setContentsMargins(0, 0, 0, 0);
95  setLayout(sceneLayout);
96 
97  // If we are making our own layout, we can create our own status area.
98  if (!status && internalizeToolBarsAndProgress)
99  status = new QStatusBar;
100 
101  // Create the tools we want
102  m_tools = new QList<MosaicTool *>;
103  m_tools->append(new MosaicSelectTool(this));
104  m_tools->append(new MosaicZoomTool(this));
105  m_tools->append(new MosaicPanTool(this));
106  m_tools->append(new MosaicControlNetTool(this));
107  m_tools->append(new MosaicAreaTool(this));
108  m_tools->append(new MosaicFindTool(this));
109  m_tools->append(new MosaicGridTool(this));
110  if (status)
111  m_tools->append(new MosaicTrackTool(this, status));
112 
113  m_tools->at(0)->activate(true);
114 
115  if (showTools) {
116 
117  if (internalizeToolBarsAndProgress) {
118  // Internalized Toolbar Layout:
119  /*
120  * -------TOOLBARS------ Colspan=2, Rowspan=1
121  * | SCENE | T |
122  * | CS=1, RS=1 | O |
123  * | | O |
124  * | | L |
125  * | | B |
126  * | | A |
127  * | | R |*Vertical tool bar CS=1, RS=1
128  * ----PROGRESS---STATUS- Colspan=2, Rowspan=1
129  *
130  *
131  */
132  QHBoxLayout *horizontalToolBarsLayout = new QHBoxLayout;
133 
134  m_permToolbar = new QToolBar("Standard Tools");
135  m_permToolbar->setWhatsThis("This area contains options that are always present in the "
136  "footprint view");
137  horizontalToolBarsLayout->addWidget(m_permToolbar);
138 
139  m_activeToolbar = new QToolBar("Active Tool", this);
140  m_activeToolbar->setObjectName("Active Tool");
141  m_activeToolbar->setWhatsThis("The currently selected tool's options will "
142  "show up here. Not all tools have options.");
143  horizontalToolBarsLayout->addWidget(m_activeToolbar);
144 
145  sceneLayout->addLayout(horizontalToolBarsLayout, 0, 0, 1, 2);
146 
147  sceneLayout->addWidget(m_graphicsView, 1, 0, 1, 1);
148 
149  m_toolpad = new ToolPad("Tool Pad", this);
150  m_toolpad->setObjectName("Tool Pad");
151  m_toolpad->setOrientation(Qt::Vertical);
152  m_toolpad->setFloatable(true);
153  sceneLayout->addWidget(m_toolpad, 1, 1, 1, 1);
154 
155  QHBoxLayout *horizontalStatusLayout = new QHBoxLayout;
156  horizontalStatusLayout->addWidget(m_progress);
157  horizontalStatusLayout->addStretch();
158  horizontalStatusLayout->addWidget(status);
159 
160  sceneLayout->addLayout(horizontalStatusLayout, 2, 0, 1, 2);
161 
162  addToPermanent(m_permToolbar);
163  m_permToolbar->addSeparator();
164 
165  addTo(m_activeToolbar);
166  addTo(m_toolpad);
167  }
168  else {
169  sceneLayout->addWidget(m_graphicsView, 0, 0, 1, 1);
170  }
171 
172  m_userToolControl = true;
173 
174  setWhatsThis("This is the mosaic scene. The opened cubes will be "
175  "shown here. You can fully interact with the files shown here.");
176 
177  getView()->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
178  getView()->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
179 
180  getView()->enableResizeZooming(false);
181 
182  connect(getView()->horizontalScrollBar(), SIGNAL(valueChanged(int)),
183  this, SLOT(sendVisibleRectChanged()));
184  connect(getView()->verticalScrollBar() , SIGNAL(valueChanged(int)),
185  this, SLOT(sendVisibleRectChanged()));
186  connect(getView()->horizontalScrollBar(), SIGNAL(rangeChanged(int, int)),
187  this, SLOT(sendVisibleRectChanged()));
188  connect(getView()->verticalScrollBar() , SIGNAL(rangeChanged(int, int)),
189  this, SLOT(sendVisibleRectChanged()));
190 
191  }
192  else {
193  sceneLayout->addWidget(m_graphicsView, 0, 0, 1, 1);
194 
195  getView()->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
196  getView()->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
197 
198  setWhatsThis("This is the mosaic world view. The opened cubes will be "
199  "shown here, but you cannot zoom in. You can select cubes by dragging "
200  "a box over them, zoom to a particular cube by right clicking on it "
201  "and selecting 'Zoom Fit', and many other actions are available.");
202  }
203 
204  // These values are OK as long as they are less than the min/greater than the max. No footprints
205  // are available yet, so 0 qualifies for both (makes a good starting point).
206  m_currentMinimumFootprintZ = 0;
207  m_currentMaximumFootprintZ = 0;
208 
209  connect(getScene(), SIGNAL(selectionChanged()),
210  this, SLOT(onSelectionChanged()));
211  // This is set up to do a single selection changed after all selections have changed, instead
212  // of 1 selection changed per 1 changed item.
213  connect(this, SIGNAL(queueSelectionChanged()),
214  this, SLOT(onQueuedSelectionChanged()), Qt::QueuedConnection);
215  }
216 
217  MosaicSceneWidget::~MosaicSceneWidget() {
218  m_outlineRect = NULL; // The scene will clean this up
219 
220  if (m_tools) {
221  foreach(MosaicTool *tool, *m_tools) {
222  delete tool;
223  tool = NULL;
224  }
225 
226  delete m_tools;
227  m_tools = NULL;
228  }
229 
230  if (m_ownProjection) {
231  delete m_projection;
232  }
233  m_projection = NULL;
234 
235  delete m_projectImageZOrders;
236  m_projectImageZOrders = NULL;
237 
238  delete m_projectViewTransform;
239  m_projectViewTransform = NULL;
240  }
241 
242 
243  void MosaicSceneWidget::setProjection(const PvlGroup &mapping) {
244  Pvl tmp;
245  tmp += mapping;
246 
247  if (!mapping.hasKeyword("EquatorialRadius")) {
248  PvlGroup radii = TProjection::TargetRadii(mapping["TargetName"]);
249  tmp.findGroup("Mapping") += radii["EquatorialRadius"];
250  tmp.findGroup("Mapping") += radii["PolarRadius"];
251  }
252 
254  m_ownProjection = true;
255  }
256 
261  PvlGroup mapping(proj->Mapping());
262 
263  if (m_mapButton) {
264  PvlKeyword projectionKeyword = mapping.findKeyword("ProjectionName");
265  QString projName = projectionKeyword[0];
266  m_mapButton->setText(tr("View/Edit %1 Projection").arg(projName));
267  }
268 
269  Projection *old = m_projection;
270  m_projection = proj;
271 
272  reprojectItems();
273  emit projectionChanged(m_projection);
274 
275  if (old && m_ownProjection) {
276  delete old;
277  old = NULL;
278  }
279 
280  m_ownProjection = false;
281  }
282 
283 
284 
285  void MosaicSceneWidget::setOutlineRect(QRectF outline) {
286  if (outline.united(getView()->sceneRect()) != getView()->sceneRect())
287  outline = QRectF();
288 
289  if (!m_outlineRect) {
290  m_outlineRect = getScene()->addRect(outline,
291  QPen(Qt::black),
292  Qt::NoBrush);
293  m_outlineRect->setZValue(DBL_MAX);
294  }
295  else {
296  m_outlineRect->setRect(outline);
297  }
298 
299  if (!m_userToolControl)
300  refit();
301  }
302 
303 
304  PvlGroup MosaicSceneWidget::createInitialProjection(
305  Image *image) {
306  Projection *proj = NULL;
307  Cube *cube = image->cube();
308  Pvl *label = cube->label();
309 
310  try {
311  proj = ProjectionFactory::CreateFromCube(*label);
312  return proj->Mapping();
313  }
314  catch(IException &) {
315  Pvl mappingPvl("$base/templates/maps/equirectangular.map");
316  PvlGroup &mappingGrp = mappingPvl.findGroup("Mapping");
317  mappingGrp += PvlKeyword("LatitudeType", "Planetocentric");
318  mappingGrp += PvlKeyword("LongitudeDirection", "PositiveEast");
319  mappingGrp += PvlKeyword("LongitudeDomain", "360");
320  mappingGrp += PvlKeyword("CenterLatitude", "0");
321  mappingGrp += PvlKeyword("CenterLongitude", "180");
322  mappingGrp += PvlKeyword("MinimumLatitude", "-90");
323  mappingGrp += PvlKeyword("MaximumLatitude", "90");
324  mappingGrp += PvlKeyword("MinimumLongitude", "0");
325  mappingGrp += PvlKeyword("MaximumLongitude", "360");
326 
327  try {
328  Camera * cam = cube->camera();
329  Distance radii[3];
330  cam->radii(radii);
331 
332  mappingGrp += PvlKeyword("TargetName", cam->target()->name());
333  mappingGrp += PvlKeyword("EquatorialRadius", toString(radii[0].meters()),
334  "meters");
335  mappingGrp += PvlKeyword("PolarRadius", toString(radii[2].meters()),
336  "meters");
337 
338  }
339  catch(IException &) {
340  mappingGrp +=
341  label->findGroup("Instrument", Pvl::Traverse)["TargetName"];
342  }
343 
344  return mappingGrp;
345  }
346  }
347 
348 
355  ImageList cubes;
356 
357  MosaicSceneItem *mosaicItem;
358  foreach(mosaicItem, *m_mosaicSceneItems) {
359  if (mosaicItem->isSelected()) {
360  cubes.append(mosaicItem->image());
361  }
362  }
363 
364  return cubes;
365  }
366 
367 
368  void MosaicSceneWidget::addToPermanent(QToolBar *perm) {
369  m_mapButton = new QToolButton(this);
370  connect(this, SIGNAL(destroyed()), m_mapButton, SLOT(deleteLater()));
371  m_mapButton->setText(tr("View/Edit/Load Map File"));
372  m_mapButton->setToolTip(tr("View/Edit/Load Map File"));
373  m_mapButton->setIcon(QIcon(FileName("$base/icons/ographic.png").expanded()));
374  m_mapButton->setWhatsThis(tr("This is the projection used by the mosaic "
375  "scene. Cubes can not be shown in the scene without a projection, so "
376  "if one is not selected, a default of Equirectangular will be used. "
377  "The selected file should be a map file, examples are available in "
378  "$base/templates/maps."));
379  m_mapButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
380  connect(m_mapButton, SIGNAL(clicked()), this, SLOT(configProjectionParameters()));
381 
382  if(m_projection) {
383  PvlKeyword projectionKeyword =
384  m_projection->Mapping().findKeyword("ProjectionName");
385  QString projName = projectionKeyword[0];
386  m_mapButton->setText(projName);
387  }
388 
389  m_quickMapAction = new QAction(tr("Quick Load Map"), this);
390  m_quickMapAction->setToolTip(tr("Quick Load Map"));
391  m_quickMapAction->setIcon(QIcon(FileName("$base/icons/quickopen.png").expanded()));
392  m_quickMapAction->setWhatsThis(tr("This is the projection used by the mosaic "
393  "scene. Cubes can not be shown in the scene without a projection, so "
394  "if one is not selected, a default of Equirectangular will be used."));
395  connect(m_quickMapAction, SIGNAL(triggered()), this, SLOT(quickConfigProjectionParameters()));
396 
397  perm->addWidget(m_mapButton);
398  perm->addAction(m_quickMapAction);
399  }
400 
401 
402  void MosaicSceneWidget::addTo(QToolBar *toolbar) {
403  MosaicTool *tool;
404  foreach(tool, *m_tools) {
405  tool->addTo(toolbar);
406  }
407  }
408 
409 
410  void MosaicSceneWidget::addTo(QMenu *menu) {
411  MosaicTool *tool;
412  foreach(tool, *m_tools) {
413  tool->addTo(menu);
414  }
415  }
416 
417 
418  void MosaicSceneWidget::addTo(ToolPad *toolPad) {
419  MosaicTool *tool;
420  foreach(tool, *m_tools) {
421  tool->addTo(toolPad);
422  }
423  }
424 
425 
431  bool MosaicSceneWidget::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) {
432  bool handled = false;
433 
434  QList<QGraphicsItem *> selectedGraphicsItems = getScene()->selectedItems();
435  QList<MosaicSceneItem *> selectedImageItems;
436  ImageList selectedImages;
437 
438  foreach (QGraphicsItem *graphicsItem, selectedGraphicsItems) {
439  MosaicSceneItem *sceneImageItem = dynamic_cast<MosaicSceneItem *>(graphicsItem);
440 
441  if (!sceneImageItem) {
442  sceneImageItem = dynamic_cast<MosaicSceneItem *>(graphicsItem->parentItem());
443  }
444 
445  if (sceneImageItem && sceneImageItem->image()) {
446  selectedImageItems.append(sceneImageItem);
447  selectedImages.append(sceneImageItem->image());
448  }
449  }
450 
451  if (selectedImageItems.count()) {
452  QMenu menu;
453 
454  QAction *title = menu.addAction(tr("%L1 Selected Images").arg(selectedImages.count()));
455  title->setEnabled(false);
456  menu.addSeparator();
457 
458  Project *project = m_directory ? m_directory->project() : NULL;
459 
460  QList<QAction *> displayActs = selectedImages.supportedActions(project);
461 
462  if (m_directory) {
463  displayActs.append(NULL);
464  displayActs.append(m_directory->supportedActions(new ImageList(selectedImages)));
465  }
466 
467  QAction *displayAct;
468  foreach(displayAct, displayActs) {
469  if (displayAct == NULL) {
470  menu.addSeparator();
471  }
472  else {
473  menu.addAction(displayAct);
474  }
475  }
476 
477  handled = true;
478  menu.exec(event->screenPos());
479  }
480 
481  return handled;
482  }
483 
484 
485  void MosaicSceneWidget::enableRubberBand(bool enable) {
486  m_customRubberBandEnabled = enable;
487  }
488 
489 
490  MosaicSceneItem *MosaicSceneWidget::cubeToMosaic(Image *image) {
491  if (image == NULL) {
492  IString msg = tr("Can not find a NULL image in the mosaic");
493  throw IException(IException::Programmer, msg, _FILEINFO_);
494  }
495 
496  return cubeToMosaic(image->displayProperties());
497  }
498 
499 
500  bool MosaicSceneWidget::blockSelectionChange(bool block) {
501  bool wasBlocking = m_blockingSelectionChanged;
502 
503  m_blockingSelectionChanged = block;
504 
505  return wasBlocking;
506  }
507 
508 
509  QProgressBar *MosaicSceneWidget::getProgress() {
510  return m_progress;
511  }
512 
513 
514  PvlObject MosaicSceneWidget::toPvl() const {
515  PvlObject output("MosaicScene");
516 
517  if (m_projection) {
518  output += m_projection->Mapping();
519 
520  QBuffer dataBuffer;
521  dataBuffer.open(QIODevice::ReadWrite);
522  QDataStream transformStream(&dataBuffer);
523  transformStream << getView()->transform();
524  dataBuffer.seek(0);
525 
526  PvlObject mosaicScenePosition("SceneVisiblePosition");
527  mosaicScenePosition += PvlKeyword("ViewTransform",
528  QString(dataBuffer.data().toHex()));
529  PvlKeyword scrollPos("ScrollPosition");
530  scrollPos += toString(getView()->horizontalScrollBar()->value());
531  scrollPos += toString(getView()->verticalScrollBar()->value());
532  mosaicScenePosition += scrollPos;
533 
534  output += mosaicScenePosition;
535 
536  MosaicTool *tool;
537  foreach(tool, *m_tools) {
538  if (tool->projectPvlObjectName() != "") {
539  PvlObject toolObj = tool->toPvl();
540  toolObj.setName(tool->projectPvlObjectName());
541  output += toolObj;
542  }
543  }
544 
545  PvlObject zOrders("ZOrdering");
546  foreach(MosaicSceneItem * mosaicSceneItem, *m_mosaicSceneItems) {
547  PvlKeyword zValue("ZValue");
548  zValue += mosaicSceneItem->image()->id();
549  zValue += toString(mosaicSceneItem->zValue());
550  zOrders += zValue;
551  }
552 
553  output += zOrders;
554  }
555  else {
556  throw IException(IException::User,
557  "Cannot save a scene without a projection to a project file",
558  _FILEINFO_);
559  }
560 
561  return output;
562  }
563 
564 
570  void MosaicSceneWidget::fromPvl(const PvlObject &project) {
571  setProjection(project.findGroup("Mapping"));
572  recalcSceneRect();
573 
574  MosaicTool *tool;
575  foreach(tool, *m_tools) {
576  if (tool->projectPvlObjectName() != "") {
577  if (project.hasObject(tool->projectPvlObjectName())) {
578  const PvlObject &toolSettings(
579  project.findObject(tool->projectPvlObjectName()));
580  tool->fromPvl(toolSettings);
581  }
582  }
583 
584  if (project.hasObject("ZOrdering")) {
585  const PvlObject &zOrders = project.findObject("ZOrdering");
586 
587  delete m_projectImageZOrders;
588  m_projectImageZOrders = NULL;
589  m_projectImageZOrders = new QHash<QString, double>;
590 
591  for (int zOrderIndex = 0;
592  zOrderIndex < zOrders.keywords();
593  zOrderIndex ++) {
594  const PvlKeyword &zOrder = zOrders[zOrderIndex];
595 
596  (*m_projectImageZOrders)[zOrder[0]] = toDouble(zOrder[1]);
597  }
598  }
599 
600  if (project.hasObject("SceneVisiblePosition")) {
601  const PvlObject &positionInfo =
602  project.findObject("SceneVisiblePosition");
603 
604  delete m_projectViewTransform;
605  m_projectViewTransform = new PvlObject(positionInfo);
606  }
607  }
608  }
609 
610 
611  void MosaicSceneWidget::load(XmlStackedHandlerReader *xmlReader) {
612  xmlReader->pushContentHandler(new XmlHandler(this));
613  }
614 
615 
616  void MosaicSceneWidget::save(QXmlStreamWriter &stream, Project *, FileName) const {
617  if (m_projection) {
618  stream.writeStartElement("footprint2DView");
619 
620  stream.writeStartElement("projection");
621  PvlGroup mapping = m_projection->Mapping();
622  std::stringstream strStream;
623  strStream << mapping;
624  stream.writeCharacters(strStream.str().c_str());
625  stream.writeEndElement();
626 
627  stream.writeStartElement("images");
628  foreach(MosaicSceneItem * mosaicSceneItem, *m_mosaicSceneItems) {
629  stream.writeStartElement("image");
630  stream.writeAttribute("id", mosaicSceneItem->image()->id());
631  stream.writeAttribute("zValue", toString(mosaicSceneItem->zValue()));
632  stream.writeEndElement();
633  }
634  stream.writeEndElement();
635 
636  stream.writeStartElement("viewTransform");
637  stream.writeAttribute("scrollBarXValue", toString(getView()->horizontalScrollBar()->value()));
638  stream.writeAttribute("scrollBarYValue", toString(getView()->verticalScrollBar()->value()));
639  QBuffer dataBuffer;
640  dataBuffer.open(QIODevice::ReadWrite);
641  QDataStream transformStream(&dataBuffer);
642  transformStream << getView()->transform();
643  dataBuffer.seek(0);
644  stream.writeCharacters(dataBuffer.data().toHex());
645  stream.writeEndElement();
646 
647  foreach(MosaicTool *tool, *m_tools) {
648  QString projectPvlObjectName = tool->projectPvlObjectName();
649  if (projectPvlObjectName != "") {
650  PvlObject toolObj = tool->toPvl();
651  toolObj.setName(projectPvlObjectName);
652 
653  stream.writeStartElement("toolData");
654  stream.writeAttribute("objectName", projectPvlObjectName);
655  std::stringstream strStream;
656  strStream << toolObj;
657  stream.writeCharacters(strStream.str().c_str());
658  stream.writeEndElement();
659  }
660  }
661 
662  stream.writeEndElement();
663  }
664  }
665 
666 
667  QRectF MosaicSceneWidget::cubesBoundingRect() const {
668  QRectF boundingRect;
669 
670  MosaicSceneItem * mosaicItem;
671  foreach(mosaicItem, *m_mosaicSceneItems) {
672  if (boundingRect.isEmpty())
673  boundingRect = mosaicItem->boundingRect();
674  else
675  boundingRect = boundingRect.united(mosaicItem->boundingRect());
676  }
677 
678  if (m_outlineRect)
679  boundingRect = boundingRect.united(m_outlineRect->boundingRect());
680 
681  return boundingRect;
682  }
683 
684 
685  MosaicSceneItem *MosaicSceneWidget::cubeToMosaic(DisplayProperties *props) {
686  if (props == NULL) {
687  IString msg = tr("Can not find a NULL Display Properties in the mosaic");
688  throw IException(IException::Programmer, msg, _FILEINFO_);
689  }
690 
691  return m_displayPropsToMosaicSceneItemMap[props];
692  }
693 
694 
695  QStringList MosaicSceneWidget::cubeFileNames() {
696  QStringList cubes;
697 
698  MosaicSceneItem *mosaicSceneItem;
699  foreach(mosaicSceneItem, *m_mosaicSceneItems) {
700  if (mosaicSceneItem->image())
701  cubes.append(mosaicSceneItem->image()->fileName());
702  }
703 
704  return cubes;
705  }
706 
707 
708  Directory *MosaicSceneWidget::directory() const {
709  return m_directory;
710  }
711 
712 
713  ImageList MosaicSceneWidget::images() {
714  ImageList images;
715 
716  MosaicSceneItem *mosaicSceneItem;
717  foreach(mosaicSceneItem, *m_mosaicSceneItems) {
718  if (mosaicSceneItem->image())
719  images.append(mosaicSceneItem->image());
720  }
721 
722  return images;
723  }
724 
725 
726  QList<QAction *> MosaicSceneWidget::getExportActions() {
727  QList<QAction *> exportActs;
728 
729  QAction *exportView = new QAction(this);
730  exportView->setText("&Export View...");
731  connect(exportView, SIGNAL(activated()), this, SLOT(exportView()));
732 
733  QAction *saveList = new QAction(this);
734  saveList->setText("Save Entire Cube List (ordered by &view)...");
735  connect(saveList, SIGNAL(activated()), this, SLOT(saveList()));
736 
737  exportActs.append(exportView);
738  exportActs.append(saveList);
739 
740  return exportActs;
741  }
742 
743 
744  QList<QAction *> MosaicSceneWidget::getViewActions() {
745  QList<QAction *> viewActs;
746 
747  foreach(MosaicTool *tool, *m_tools) {
748  QList<QAction *> toolViewActs = tool->getViewActions();
749  viewActs.append(toolViewActs);
750  }
751 
752  return viewActs;
753  }
754 
755 
760  QList<QAction *> results;
761 
762  bool allImagesInView = !images->isEmpty();
763 
764  foreach (Image *image, *images) {
765  allImagesInView = allImagesInView && (cubeToMosaic(image) != NULL);
766  }
767 
768  if (allImagesInView) {
769  MoveToTopSceneWorkOrder *moveToTopAct =
770  new MoveToTopSceneWorkOrder(this, m_directory->project());
771  moveToTopAct->setData(images);
772  results.append(moveToTopAct);
773 
774  MoveUpOneSceneWorkOrder *moveUpOneAct =
775  new MoveUpOneSceneWorkOrder(this, m_directory->project());
776  moveUpOneAct->setData(images);
777  results.append(moveUpOneAct);
778 
779  MoveToBottomSceneWorkOrder *moveToBottomAct =
780  new MoveToBottomSceneWorkOrder(this, m_directory->project());
781  moveToBottomAct->setData(images);
782  results.append(moveToBottomAct);
783 
784  MoveDownOneSceneWorkOrder *moveDownOneAct =
785  new MoveDownOneSceneWorkOrder(this, m_directory->project());
786  moveDownOneAct->setData(images);
787  results.append(moveDownOneAct);
788 
789  results.append(NULL);
790 
791  QAction *zoomFitAct = new QAction(tr("Zoom Fit"), this);
792  zoomFitAct->setData(qVariantFromValue(images));
793  connect(zoomFitAct, SIGNAL(triggered()), this, SLOT(fitInView()));
794  results.append(zoomFitAct);
795  }
796 
797  return results;
798  }
799 
800 
801  QWidget * MosaicSceneWidget::getControlNetHelp(QWidget *cnetToolContainer) {
802  QScrollArea *cnetHelpWidgetScrollArea = new QScrollArea;
803 
804  QWidget *cnetHelpWidget = new QWidget;
805 
806  QVBoxLayout *cnetHelpLayout = new QVBoxLayout;
807  cnetHelpWidget->setLayout(cnetHelpLayout);
808 
809  QLabel *title = new QLabel("<h2>Control Networks</h2>");
810  cnetHelpLayout->addWidget(title);
811 
812  QPixmap previewPixmap;
813 
814  if (cnetToolContainer) {
815  previewPixmap = QPixmap::grabWidget(cnetToolContainer).scaled(
816  QSize(500, 200), Qt::KeepAspectRatio, Qt::SmoothTransformation);
817  }
818  else {
819  ToolPad tmpToolPad("Example Tool Pad", NULL);
820  MosaicControlNetTool tmpTool(NULL);
821  tmpTool.addTo(&tmpToolPad);
822 
823  tmpToolPad.resize(QSize(32, 32));
824 
825  previewPixmap = QPixmap::grabWidget(&tmpToolPad);
826  }
827 
828  QLabel *previewWrapper = new QLabel;
829  previewWrapper->setPixmap(previewPixmap);
830  cnetHelpLayout->addWidget(previewWrapper);
831 
832  QLabel *overview = new QLabel("The mosaic scene can display control points "
833  "in addition to the usual cube footprints. This feature is currently "
834  "offered as one of the Mosaic Scene's tools. To open a network, click "
835  "on the control network tool. It will immediately prompt you for a "
836  "control network file if one is not open. Only control points for "
837  "which the latitude and longitude can be established will be "
838  "displayed. Other control points will be ignored by qmos.<br><br>"
839  "<b>Warning: Opening large control networks is slow.</b>"
840  "<h3>Control Network Tool Options</h3>"
841  "<ul>"
842  "<li>The control network tool opens control networks in two ways. "
843  "First, if you select the control network tool and no network is "
844  "open, then it will prompt you for one. Second, if there is an open "
845  "network, the buttons for the available options are displayed in the "
846  "active tool area.</li>"
847  "<li>The control network tool can toggle whether or not control "
848  "points are displayed on the screen using the 'Display' button. "
849  "Control points are always on top and colored based on their "
850  "ignored, locked and type values.</li>"
851  "<li>This tool can also change the color of your footprints based on "
852  "connectivity through control points. This is available through the "
853  "'Color Islands' button. When you press color islands, all of the "
854  "current cube coloring information is lost and re-done based on "
855  "how the control network connects the files. Each set of connected "
856  "cubes are colored differently; generally speaking, islands are not "
857  "a good thing to have in your control network.</li>"
858  "<li>This tool will color your footprints on a per-image basis if you "
859  "click color images, effectively reversing color islands.</li>"
860  "<li>The show movement option under 'Configure Movement Display' "
861  "only displays data when the control "
862  "network has adjusted values. This means that show movement only "
863  "works after you have done a jigsaw solution on the control network. "
864  "This displays arrows emanating from the apriori latitude/longitude "
865  "and pointing toward the adjusted latitude/longitude.</li>");
866  overview->setWordWrap(true);
867  cnetHelpLayout->addWidget(overview);
868 
869  cnetHelpWidgetScrollArea->setWidget(cnetHelpWidget);
870 
871  return cnetHelpWidgetScrollArea;
872  }
873 
874 
875  QWidget * MosaicSceneWidget::getGridHelp(QWidget *gridToolContainer) {
876  QScrollArea *gridHelpWidgetScrollArea = new QScrollArea;
877 
878  QWidget *gridHelpWidget = new QWidget;
879 
880  QVBoxLayout *gridHelpLayout = new QVBoxLayout;
881  gridHelpWidget->setLayout(gridHelpLayout);
882 
883  QLabel *title = new QLabel("<h2>Map Grid Tool</h2>");
884  gridHelpLayout->addWidget(title);
885 
886  QPixmap previewPixmap;
887 
888  if (gridToolContainer) {
889  previewPixmap = QPixmap::grabWidget(gridToolContainer).scaled(
890  QSize(500, 200), Qt::KeepAspectRatio, Qt::SmoothTransformation);
891  }
892  else {
893  ToolPad tmpToolPad("Example Tool Pad", NULL);
894  MosaicGridTool tmpTool(NULL);
895  tmpTool.addTo(&tmpToolPad);
896 
897  tmpToolPad.resize(QSize(32, 32));
898 
899  previewPixmap = QPixmap::grabWidget(&tmpToolPad);
900  }
901 
902  QLabel *previewWrapper = new QLabel;
903  previewWrapper->setPixmap(previewPixmap);
904  gridHelpLayout->addWidget(previewWrapper);
905 
906  QLabel *overview = new QLabel("Superimpose a map grid over the area of "
907  "displayed footprints in the 'mosaic scene.'"
908  "<h2>Overview</h2>"
909  "<ul>"
910  "<li>The Map Grid Tool is activated by selecting the 'cross-hatch' "
911  "icon or typing 'g' at the keyboard."
912  "</li>"
913  "<li>The parameter options are displayed below the menubar. "
914  "Clicking the 'Grid Options' button will open the dialog. Checking "
915  "'Auto Grid' will draw a grid based on the open cubes. Hitting "
916  "'Show Grid' will display or hide the grid."
917  "</li>"
918  "<li>The map grid is defined by the loaded Map File (just as the "
919  "footprints and image data are), the opened cubes, or the grid "
920  "tool parameters."
921  "</li>"
922  "<li>If a Map File has not been selected, the default "
923  "Equirectangular projection will be used. The resulting grid "
924  "lines in the default 'Equi' map file will be drawn for the "
925  "full global range (latitude range = -90,90; longitude range = "
926  "0,360) at the default latitude and longitude increment values."
927  "</li>"
928  "<li>"
929  "If the grid lines are not immediately visible, try to "
930  "'zoom out' in the 'mosaic scene' window and modify the "
931  "Latitude and Longitude Increment parameters."
932  "</li>"
933  "</ul>"
934  "<strong>Options:</strong>"
935  "<ul>"
936  "<li>The 'Show Grid' option draws (checked) or clears (unchecked) the grid."
937  "</li>"
938  "<li>The 'Auto Grid' option draws a grid with extents and increments "
939  "computed from the set of images that are opened. The values displayed in the dialog "
940  "will reflect those used to draw the grid."
941  "</li>"
942  "<li>The expected units for each entry are displayed to the right of the "
943  "dialog box."
944  "</li>"
945  "<li>The 'Extent Type' combo boxes allow you to pick the source of the "
946  "grid extents from the map file, from the open cubes <default>, or manually "
947  "entered."
948  "</li>"
949  "<li>The 'Auto Apply' checkbox, inside the 'Grid Options' dialog box, allows you to see "
950  "real time updates in the grid when you change the parameters."
951  "</li>"
952  "<li> Depending on the projection, the grid may not behave as expected. For instance, "
953  "with a polarstereographic projection, the pole will not be included in the 'Auto "
954  "Grid' if it is not in the cube region. In this case the 'Manual' option for latitude "
955  "extents allows you to force the grid to the pole."
956  "</li>"
957  "</ul>");
958  overview->setWordWrap(true);
959  gridHelpLayout->addWidget(overview);
960 
961  gridHelpWidgetScrollArea->setWidget(gridHelpWidget);
962 
963  return gridHelpWidgetScrollArea;
964  }
965 
966 
967  QWidget * MosaicSceneWidget::getLongHelp(QWidget *sceneContainer) {
968  QScrollArea *longHelpWidgetScrollArea = new QScrollArea;
969 
970  QWidget *longHelpWidget = new QWidget;
971 
972  QVBoxLayout *longHelpLayout = new QVBoxLayout;
973  longHelpWidget->setLayout(longHelpLayout);
974 
975  QLabel *title = new QLabel("<h2>Mosaic Scene</h2>");
976  longHelpLayout->addWidget(title);
977 
978  if (sceneContainer) {
979  QPixmap previewPixmap = QPixmap::grabWidget(sceneContainer).scaled(
980  QSize(500, 200), Qt::KeepAspectRatio, Qt::SmoothTransformation);
981 
982  QLabel *previewWrapper = new QLabel;
983  previewWrapper->setPixmap(previewPixmap);
984  longHelpLayout->addWidget(previewWrapper);
985  }
986 
987  QLabel *overview = new QLabel("The mosaic scene displays cube footprints "
988  "to show where files are on a target and how they overlap. "
989  "The scene always represents projected image space and cannot show raw "
990  "or unprojected images; images will be projected on the fly."
991  "<h3>Tools</h3>"
992  "<p>Interact with the mosaic scene in different ways using "
993  "the tools. The tools are usually in a toolbar next to the scene. "
994  "The tools define what is displayed and what happens when you "
995  "click in the mosaic scene. The tools include</p>"
996  "<ul><li>Select Tool</li>"
997  "<li>Zoom Tool</li>"
998  "<li>Pan Tool</li>"
999  "<li>Control Network Tool</li>"
1000  "<li>Show Area Tool</li>"
1001  "<li>Find Tool</li>"
1002  "<li>Grid Tool</li></ul>"
1003  "<h3>Context Menus</h3>"
1004  "Right click on anything in the mosaic scene and a context menu will pop up showing "
1005  "a list of actions or information relevant to the item you clicked on. "
1006  "<p>Note: The context menu is not associated with any selection, only the item "
1007  "clicked on.</p>");
1008  overview->setWordWrap(true);
1009  longHelpLayout->addWidget(overview);
1010 
1011  longHelpWidgetScrollArea->setWidget(longHelpWidget);
1012 
1013  return longHelpWidgetScrollArea;
1014  }
1015 
1016 
1017  QWidget * MosaicSceneWidget::getMapHelp(QWidget *mapContainer) {
1018  QScrollArea *mapHelpWidgetScrollArea = new QScrollArea;
1019 
1020  QWidget *mapHelpWidget = new QWidget;
1021 
1022  QVBoxLayout *mapHelpLayout = new QVBoxLayout;
1023  mapHelpWidget->setLayout(mapHelpLayout);
1024 
1025  QLabel *title = new QLabel(tr("<h2>Map File</h2>"));
1026  mapHelpLayout->addWidget(title);
1027 
1028  if (mapContainer) {
1029  QPixmap previewPixmap = QPixmap::grabWidget(mapContainer).scaled(
1030  QSize(500, 200), Qt::KeepAspectRatio, Qt::SmoothTransformation);
1031 
1032  QLabel *previewWrapper = new QLabel;
1033  previewWrapper->setPixmap(previewPixmap);
1034  mapHelpLayout->addWidget(previewWrapper);
1035  }
1036 
1037  QLabel *overviewMapIcon = new QLabel;
1038 
1039  overviewMapIcon->setPixmap(
1040  QIcon(FileName("$base/icons/ographic.png").expanded()).pixmap(32, 32));
1041  mapHelpLayout->addWidget(overviewMapIcon);
1042 
1043  QLabel *defaultMapFile = new QLabel(tr(
1044  "<h3>Default Map File</h3>"
1045  "The mosaic scene's projection is defined by a \"Map File\" that consists of keywords "
1046  "that describe the map layout to be used. If a cube or a list of cubes are "
1047  "loaded before a map file is selected, the default map file defines the "
1048  "equirectangular projection, planetocentric latitude, positive longitude east, 360 "
1049  "longitude domain, latitude range=90S-90N, longitude range=0-360E. The radius will "
1050  "default to the IAU standards (ellipsoid or sphere) for the specific planetary body "
1051  "defined for the \"TargetName\" in the labels of the image cube(s)."));
1052 
1053  defaultMapFile->setWordWrap(true);
1054  mapHelpLayout->addWidget(defaultMapFile);
1055 
1056  QLabel *userDefinedMapFileOverview = new QLabel(tr(
1057  "<h3>User Defined Map File</h3>"
1058  "You can load an existing \"Map File\" before loading images into %1 by selecting the "
1059  "\"View/Edit/Load Map File\" option. You will be greeted with a dialog box that will "
1060  "enable you to select an existing map file by clicking on \"Load Map File.\" Once "
1061  "the map file is selected, the contents is displayed in the dialog box where "
1062  "modifications can be made as well. If the modified map file is to be used later, "
1063  "save the map file by clicking on \"Save Map File\" button.")
1064  .arg(QCoreApplication::applicationName()));
1065 
1066  userDefinedMapFileOverview->setWordWrap(true);
1067  mapHelpLayout->addWidget(userDefinedMapFileOverview);
1068 
1069  QLabel *userDefinedMapFileQuickLoad = new QLabel(tr(
1070  "The \"Quick Load Map\" option (lightning icon) allows you to efficiently select a "
1071  "prepared \"Map File\" without an immediate need to view or edit the contents."));
1072 
1073  userDefinedMapFileQuickLoad->setWordWrap(true);
1074  mapHelpLayout->addWidget(userDefinedMapFileQuickLoad);
1075 
1076  QLabel *userDefinedMapFileAnyTime = new QLabel(tr(
1077  "At any point, you have access to the \"View/Edit\" functionality to modify or load a "
1078  "different map file."));
1079 
1080  userDefinedMapFileAnyTime->setWordWrap(true);
1081  mapHelpLayout->addWidget(userDefinedMapFileAnyTime);
1082 
1083  QString mapProjWorkshopUrl("http://isis.astrogeology.usgs.gov/IsisWorkshop/"
1084  "index.php/Learning_About_Map_Projections");
1085  QLabel *preparingMapFile = new QLabel(tr(
1086  "<h3>Preparing a Map File</h3>"
1087  "Please refer to Isis applications such as 'maptemplate' or 'mosrange' for more details "
1088  "on creating a custom map file that defines the desired projection, latitude "
1089  "system, and longitude direction and domain. This program will use the latitude range "
1090  "and longitude range if they exist in the loaded file. A choice of map templates that can be used as "
1091  "a starting point for supported map projections can be found in $base/templates/maps (refer "
1092  "to maptemplate or mosrange for more details and information on the required parameters "
1093  "for a projection). Note that through the file name selection box, $base will need "
1094  "to be replaced with the specific Isis3 system path. The website: "
1095  "<a href='%1'>%1</a> also provides useful information about map projections.")
1096  .arg(mapProjWorkshopUrl));
1097 
1098  preparingMapFile->setOpenExternalLinks(true);
1099  preparingMapFile->setWordWrap(true);
1100  mapHelpLayout->addWidget(preparingMapFile);
1101 
1102  QLabel *mapFileDisplayResults = new QLabel(tr(
1103  "<h3>Display Results with the Map File</h3>"
1104  "The footprints and image data that are displayed in the mosaic scene are defined by the "
1105  "loaded \"Map File\" regardless of whether the opened cubes are Level1 (raw "
1106  "camera space) or Level2 (map projected). The associated footprint polygons for "
1107  "Level2 cubes will be re-mapped as needed based on the loaded map file."));
1108 
1109  mapFileDisplayResults->setWordWrap(true);
1110  mapHelpLayout->addWidget(mapFileDisplayResults);
1111 
1112  QLabel *editingMapFileOverview = new QLabel(tr(
1113  "<h3>Editing a Map File</h3>"
1114  "Editing a map file is possible through the dialog box displayed by clicking on the "
1115  "'View/Edit/Load Map File' icon/button. The edits are "
1116  "applied to the current session and will be included with a 'Saved Project' (refer to "
1117  "the help under File-Save Project or Save Project as)."));
1118 
1119  editingMapFileOverview->setWordWrap(true);
1120  mapHelpLayout->addWidget(editingMapFileOverview);
1121 
1122  QLabel *saveMapFileToDiskBullet = new QLabel(tr(
1123  "<ul>"
1124  "<li>"
1125  "To save or write the changes to a map file on disk, choose 'Save Map File' button. "
1126  "Map files can be saved to an existing map file (overwrites) or to a new file. This "
1127  "program always saves <strong>exactly</strong> what you see, the text, in the dialog "
1128  "box."
1129  "</li>"
1130  "</ul>"));
1131 
1132  saveMapFileToDiskBullet->setWordWrap(true);
1133  mapHelpLayout->addWidget(saveMapFileToDiskBullet);
1134 
1135  QLabel *mapFileValidityBullet = new QLabel(tr(
1136  "<ul>"
1137  "<li>"
1138  "As you modify the contents of a loaded map file in the dialog box, the entry is "
1139  "verified as you type with a bold black indicator message displaying whether the "
1140  "text is valid or is not valid. If you want to see the actual error messages, "
1141  "select the 'Show Errors' box and the errors will be displayed in red font "
1142  "along with the black bolded message. The errors will update "
1143  "as you type."
1144  "</li>"
1145  "</ul>"));
1146 
1147  mapFileValidityBullet->setWordWrap(true);
1148  mapHelpLayout->addWidget(mapFileValidityBullet);
1149 
1150  QLabel *mapFileCommentsBullet = new QLabel(tr(
1151  "<ul>"
1152  "<li>"
1153  "Map files may contain 'commented-out' lines (text that starts with \"#\" at "
1154  "the beginning of the line). These are referred to as \"unnecessary\""
1155  "or \"unknown\" keywords, they are simply ignored. If these lines are to be saved to "
1156  "the output map file on disk, click 'Save Map File' BEFORE clicking 'Ok' or 'Apply.' "
1157  "The comments are removed from the dialog box when you hit 'Ok' or 'Apply,' if they "
1158  "are just above \"End_Group\" or follow \"End_Group\" or \"End\".<br/><br/>"
1159 
1160  "If you want these comments retained, make sure they are immediately above a valid "
1161  "keyword inside of \"Group = Mapping.\" Note that any lines (commented or not) will "
1162  "not be saved if they are placed outside of \"Group = Mapping\" and \"End_Group\"."
1163  "</li>"
1164  "</ul>"));
1165 
1166  mapFileCommentsBullet->setWordWrap(true);
1167  mapHelpLayout->addWidget(mapFileCommentsBullet);
1168 
1169  mapHelpWidgetScrollArea->setWidget(mapHelpWidget);
1170 
1171  return mapHelpWidgetScrollArea;
1172  }
1173 
1174 
1175  QWidget * MosaicSceneWidget::getPreviewHelp(QWidget *worldViewContainer) {
1176  QScrollArea *previewHelpWidgetScrollArea = new QScrollArea;
1177 
1178  QWidget *previewHelpWidget = new QWidget;
1179 
1180  QVBoxLayout *previewHelpLayout = new QVBoxLayout;
1181  previewHelpWidget->setLayout(previewHelpLayout);
1182 
1183  QLabel *title = new QLabel("<h2>Mosaic World View</h2>");
1184  previewHelpLayout->addWidget(title);
1185 
1186  if (worldViewContainer) {
1187  QPixmap previewPixmap = QPixmap::grabWidget(worldViewContainer).scaled(
1188  QSize(500, 200), Qt::KeepAspectRatio, Qt::SmoothTransformation);
1189 
1190  QLabel *previewWrapper = new QLabel;
1191  previewWrapper->setPixmap(previewPixmap);
1192  previewHelpLayout->addWidget(previewWrapper);
1193  }
1194 
1195  QLabel *overview = new QLabel("The mosaic world view displays cube "
1196  "footprints to show you where your files are on a target and their "
1197  "general arrangement. The world view does not have tools like "
1198  "mosaic scenes, but otherwise they are very similar.");
1199  overview->setWordWrap(true);
1200  previewHelpLayout->addWidget(overview);
1201 
1202  previewHelpWidgetScrollArea->setWidget(previewHelpWidget);
1203 
1204  return previewHelpWidgetScrollArea;
1205  }
1206 
1207 
1208  MosaicSceneItem *MosaicSceneWidget::addImage(Image *image) {
1209  if (m_projection == NULL) {
1210  setProjection(createInitialProjection(image));
1211  }
1212 
1213  MosaicSceneItem *mosItem = NULL;
1214 
1215  // Verify we don't have this cube already... if we do, ignore the add request
1216  if (!cubeToMosaic(image)) {
1217  mosItem = new MosaicSceneItem(image, this);
1218 
1219  connect(mosItem, SIGNAL(changed(const QList<QRectF> &)),
1220  m_graphicsView, SLOT(updateScene(const QList<QRectF> &)));
1221 
1222  // We want everything to have a unique Z value so we can manage the z order
1223  // well.
1224  if (m_projectImageZOrders && m_projectImageZOrders->contains(image->id())) {
1225  double zOrder = m_projectImageZOrders->value(image->id());
1226  m_projectImageZOrders->remove(image->id());
1227 
1228  foreach (MosaicSceneItem *mosaicItem, *m_mosaicSceneItems) {
1229  if (mosaicItem->zValue() == zOrder) {
1230  mosaicItem->setZValue(maximumZ() + 1);
1231  m_currentMaximumFootprintZ = maximumZ() + 1;
1232  }
1233  }
1234 
1235  m_currentMaximumFootprintZ = qMax(zOrder, maximumZ());
1236  mosItem->setZValue(zOrder);
1237  }
1238  else {
1239  mosItem->setZValue(maximumZ() + 1);
1240  m_currentMaximumFootprintZ = maximumZ() + 1;
1241  }
1242 
1243  getScene()->addItem(mosItem);
1244  m_mosaicSceneItems->append(mosItem);
1245  m_displayPropsToMosaicSceneItemMap[image->displayProperties()] = mosItem;
1246 
1247  connect(mosItem, SIGNAL(destroyed(QObject *)),
1248  this, SLOT(removeMosItem(QObject *)));
1249 
1250  DisplayProperties *prop = image->displayProperties();
1251  connect(prop, SIGNAL(moveDownOne()),
1252  this, SLOT(moveDownOne()));
1253  connect(prop, SIGNAL(moveToBottom()),
1254  this, SLOT(moveToBottom()));
1255  connect(prop, SIGNAL(moveUpOne()),
1256  this, SLOT(moveUpOne()));
1257  connect(prop, SIGNAL(moveToTop()),
1258  this, SLOT(moveToTop()));
1259  connect(prop, SIGNAL(zoomFit()),
1260  this, SLOT(fitInView()));
1261  }
1262 
1263  return mosItem;
1264  }
1265 
1266 
1267  double MosaicSceneWidget::maximumZ() {
1268  return m_currentMaximumFootprintZ;
1269  }
1270 
1271 
1272  double MosaicSceneWidget::minimumZ() {
1273  return m_currentMinimumFootprintZ;
1274  }
1275 
1276  void MosaicSceneWidget::recalcSceneRect() {
1277  if (m_projection) {
1278  double minX, minY, maxX, maxY;
1279  m_projection->XYRange(minX, maxX, minY, maxY);
1280 
1281  QRectF projRect(minX, -maxY, maxX - minX, maxY - minY);
1282  QRectF cubesBounding = cubesBoundingRect();
1283 
1284  QRectF bounding = projRect.united(cubesBounding);
1285 
1286  if (m_outlineRect && m_outlineRect->isVisible())
1287  bounding = bounding.united(m_outlineRect->boundingRect());
1288 
1289  getView()->setSceneRect(bounding);
1290  }
1291  }
1292 
1293  void MosaicSceneWidget::addImages(ImageList images) {
1294  if (m_userToolControl)
1295  m_progress->setText("Loading primary scene");
1296  else
1297  m_progress->setText("Loading secondary scene");
1298 
1299  m_progress->setRange(0, images.size() - 1);
1300  m_progress->setValue(0);
1301  m_progress->setVisible(true);
1302 
1303  foreach(Image *image, images) {
1304  try {
1305  addImage(image);
1306  }
1307  catch(IException &e) {
1308  e.print();
1309  }
1310 
1311  m_progress->setValue(m_progress->value() + 1);
1312  }
1313 
1314  recalcSceneRect();
1315 
1316  if (m_projectViewTransform) {
1317  PvlObject &positionInfo = *m_projectViewTransform;
1318  QByteArray hexValues(positionInfo["ViewTransform"][0].toAscii());
1319  QDataStream transformStream(QByteArray::fromHex(hexValues));
1320 
1321  QTransform viewTransform;
1322  transformStream >> viewTransform;
1323  getView()->setTransform(viewTransform);
1324 
1325  QPoint projectScrollPos(toInt(positionInfo["ScrollPosition"][0]),
1326  toInt(positionInfo["ScrollPosition"][1]));
1327 
1328  getView()->horizontalScrollBar()->setValue(projectScrollPos.x());
1329  getView()->verticalScrollBar()->setValue(projectScrollPos.y());
1330  }
1331  else {
1332  refit();
1333  }
1334 
1335  if (!m_projectImageZOrders || m_projectImageZOrders->isEmpty()) {
1336  delete m_projectViewTransform;
1337  m_projectViewTransform = NULL;
1338  }
1339 
1340  m_progress->setVisible(false);
1341  emit cubesChanged();
1342  }
1343 
1344 
1349  QString output =
1350  QFileDialog::getSaveFileName((QWidget *)parent(),
1351  "Choose output file",
1352  QDir::currentPath() + "/untitled.png",
1353  QString("Images (*.png *.jpg *.tif)"));
1354  if (output.isEmpty()) return;
1355 
1356  // Use png format is the user did not add a suffix to their output filename.
1357  if (QFileInfo(output).suffix().isEmpty()) {
1358  output = output + ".png";
1359  }
1360 
1361  QString format = QFileInfo(output).suffix();
1362  QPixmap pm = QPixmap::grabWidget(getScene()->views().last());
1363 
1364  std::string formatString = format.toStdString();
1365  if (!pm.save(output, formatString.c_str())) {
1366  QMessageBox::information(this, "Error",
1367  "Unable to save [" + output + "]");
1368  }
1369  }
1370 
1371 
1372  void MosaicSceneWidget::saveList() {
1373  QString output =
1374  QFileDialog::getSaveFileName((QWidget *)parent(),
1375  "Choose output file",
1376  QDir::currentPath() + "/files.lis",
1377  QString("List File (*.lis);;Text File (*.txt);;All Files (*.*)"));
1378  if (output.isEmpty()) return;
1379 
1380  TextFile file(output, "overwrite");
1381 
1382  QList<MosaicSceneItem *> sorted = *m_mosaicSceneItems;
1383  qSort(sorted.begin(), sorted.end(), zOrderGreaterThan);
1384 
1385  MosaicSceneItem *sceneItem;
1386  foreach(sceneItem, sorted) {
1387  file.PutLine( sceneItem->image()->fileName() );
1388  }
1389  }
1390 
1391 
1392  void MosaicSceneWidget::removeMosItem(QObject *mosItem) {
1393  MosaicSceneItem *castedMosItem = (MosaicSceneItem *) mosItem;
1394  m_mosaicSceneItems->removeAll(castedMosItem);
1395  m_displayPropsToMosaicSceneItemMap.remove(
1396  m_displayPropsToMosaicSceneItemMap.key(castedMosItem));
1397  recalcSceneRect();
1398  emit cubesChanged();
1399  }
1400 
1401 
1407  QRectF sceneRect = cubesBoundingRect();
1408 
1409  if (sceneRect.isEmpty())
1410  return;
1411 
1412  double xPadding = sceneRect.width() * 0.10;
1413  double yPadding = sceneRect.height() * 0.10;
1414 
1415  sceneRect.adjust(-xPadding, -yPadding, xPadding, yPadding);
1416  getView()->fitInView(sceneRect, Qt::KeepAspectRatio);
1417  }
1418 
1419 
1420  void MosaicSceneWidget::setCubesSelectable(bool selectable) {
1421  if (m_cubesSelectable != selectable) {
1422  m_cubesSelectable = selectable;
1423 
1424  MosaicSceneItem *mosaicSceneItem;
1425  foreach(mosaicSceneItem, *m_mosaicSceneItems) {
1426  mosaicSceneItem->scenePropertiesChanged();
1427  }
1428  }
1429  }
1430 
1431 
1437  ProjectionConfigDialog configDialog(this);
1438  configDialog.exec();
1439  }
1440 
1441 
1442  void MosaicSceneWidget::quickConfigProjectionParameters() {
1443  ProjectionConfigDialog configDialog(this);
1444  configDialog.setQuickConfig(true);
1445  configDialog.exec();
1446  }
1447 
1448 
1449  void MosaicSceneWidget::sendVisibleRectChanged() {
1450  QPointF topLeft = getView()->mapToScene(0, 0);
1451  QPointF bottomRight = getView()->mapToScene(
1452  (int)getView()->width(),
1453  (int)getView()->height());
1454 
1455  QRectF visibleRect(topLeft, bottomRight);
1456  emit visibleRectChanged(visibleRect);
1457  }
1458 
1459 
1460  bool MosaicSceneWidget::eventFilter(QObject *obj, QEvent *event) {
1461  bool stopProcessingEvent = true;
1462 
1463  switch(event->type()) {
1464  case QMouseEvent::GraphicsSceneMousePress: {
1465  if (m_customRubberBandEnabled) {
1466  // Intiate the rubber banding!
1467  if (!m_customRubberBand) {
1468  m_customRubberBand = new QRubberBand(QRubberBand::Rectangle,
1469  getView());
1470  }
1471 
1472  if (!m_rubberBandOrigin) {
1473  m_rubberBandOrigin = new QPoint;
1474  }
1475 
1476  *m_rubberBandOrigin = getView()->mapFromScene(
1477  ((QGraphicsSceneMouseEvent *)event)->scenePos());
1478  m_customRubberBand->setGeometry(QRect(*m_rubberBandOrigin, QSize()));
1479  m_customRubberBand->show();
1480  }
1481 
1482  emit mouseButtonPress(
1483  ((QGraphicsSceneMouseEvent *)event)->scenePos(),
1484  ((QGraphicsSceneMouseEvent *)event)->button());
1485 
1486  stopProcessingEvent = false;
1487  break;
1488  }
1489 
1490  case QMouseEvent::GraphicsSceneMouseRelease: {
1491  bool signalEmitted = false;
1492  if (m_customRubberBandEnabled && m_rubberBandOrigin &&
1493  m_customRubberBand) {
1494  if (m_customRubberBand->geometry().width() +
1495  m_customRubberBand->geometry().height() > 10) {
1496  emit rubberBandComplete(
1497  getView()->mapToScene(
1498  m_customRubberBand->geometry()).boundingRect(),
1499  ((QGraphicsSceneMouseEvent *)event)->button());
1500  signalEmitted = true;
1501  }
1502 
1503  delete m_rubberBandOrigin;
1504  m_rubberBandOrigin = NULL;
1505 
1506  delete m_customRubberBand;
1507  m_customRubberBand = NULL;
1508  }
1509 
1510  if (!signalEmitted) {
1511  stopProcessingEvent = false;
1512  emit mouseButtonRelease(
1513  ((QGraphicsSceneMouseEvent *)event)->scenePos(),
1514  ((QGraphicsSceneMouseEvent *)event)->button());
1515  }
1516  break;
1517  }
1518 
1519  case QMouseEvent::GraphicsSceneMouseDoubleClick:
1520  emit mouseDoubleClick(
1521  ((QGraphicsSceneMouseEvent *)event)->scenePos());
1522  stopProcessingEvent = false;
1523  break;
1524 
1525  case QMouseEvent::GraphicsSceneMouseMove:
1526  if (m_customRubberBandEnabled && m_rubberBandOrigin &&
1527  m_customRubberBand) {
1528  QPointF scenePos = ((QGraphicsSceneMouseEvent *)event)->scenePos();
1529  QPoint screenPos = getView()->mapFromScene(scenePos);
1530 
1531  QRect rubberBandRect =
1532  QRect(*m_rubberBandOrigin, screenPos).normalized();
1533 
1534  m_customRubberBand->setGeometry(rubberBandRect);
1535  }
1536  else {
1537  stopProcessingEvent = false;
1538  }
1539 
1540  emit mouseMove(
1541  ((QGraphicsSceneMouseEvent *)event)->scenePos());
1542  break;
1543 
1544  case QEvent::GraphicsSceneWheel:
1545  emit mouseWheel(
1546  ((QGraphicsSceneWheelEvent *)event)->scenePos(),
1547  ((QGraphicsSceneWheelEvent *)event)->delta());
1548  event->accept();
1549  stopProcessingEvent = true;
1550  break;
1551 
1552  case QMouseEvent::Enter:
1553  emit mouseEnter();
1554  stopProcessingEvent = false;
1555  break;
1556 
1557  case QMouseEvent::Leave:
1558  emit mouseLeave();
1559  stopProcessingEvent = false;
1560  break;
1561 
1562  case QEvent::GraphicsSceneHelp: {
1563  setToolTip("");
1564  bool toolTipFound = false;
1565 
1566  QGraphicsItem *sceneItem;
1567  foreach(sceneItem, getScene()->items()) {
1568  if (!toolTipFound) {
1569  if (sceneItem->contains(
1570  ((QGraphicsSceneHelpEvent*)event)->scenePos()) &&
1571  sceneItem->toolTip().size() > 0) {
1572  setToolTip(sceneItem->toolTip());
1573  toolTipFound = true;
1574  }
1575  }
1576  }
1577 
1578  if (toolTipFound) {
1579  stopProcessingEvent = true;
1580  QToolTip::showText(
1581  ((QGraphicsSceneHelpEvent*)event)->screenPos(),
1582  toolTip());
1583  }
1584  break;
1585  }
1586 
1587  default:
1588  stopProcessingEvent = false;
1589  break;
1590  }
1591 
1592  return stopProcessingEvent;
1593  }
1594 
1595 
1603  if (m_mosaicSceneItems->size() == 0)
1604  return;
1605 
1606  if (m_userToolControl)
1607  m_progress->setText("Reprojecting primary scene");
1608  else
1609  m_progress->setText("Reprojecting secondary scene");
1610 
1611  // This gives some pretty graphics as thing work
1612  int reprojectsPerUpdate = qMax(1, m_mosaicSceneItems->size() / 20);
1613 
1614  m_progress->setRange(0,
1615  (m_mosaicSceneItems->size() - 1) / reprojectsPerUpdate + 1);
1616  m_progress->setValue(0);
1617  m_progress->setVisible(true);
1618 
1619  MosaicSceneItem *mosaicSceneItem;
1620 
1621  int progressCountdown = reprojectsPerUpdate;
1622  foreach(mosaicSceneItem, *m_mosaicSceneItems) {
1623  try {
1624  mosaicSceneItem->reproject();
1625  }
1626  catch(IException &e) {
1627  IString msg = "The file [";
1628 
1629  if (mosaicSceneItem->image())
1630  msg += (IString)mosaicSceneItem->image()->displayProperties()->displayName();
1631 
1632  msg += "] is being removed due to not being able to project onto the scene";
1633 
1635  tmp.print();
1636  mosaicSceneItem->image()->deleteLater();
1637  }
1638 
1639  progressCountdown --;
1640  if (progressCountdown == 0) {
1641  m_progress->setValue(m_progress->value() + 1);
1642  progressCountdown = reprojectsPerUpdate;
1643  refit();
1644  }
1645  }
1646 
1647  m_progress->setValue(m_progress->maximum());
1648 
1649  recalcSceneRect();
1650  refit();
1651  m_progress->setVisible(false);
1652  }
1653 
1654 
1655  void MosaicSceneWidget::moveDownOne() {
1656  DisplayProperties *props = qobject_cast<DisplayProperties *>(sender());
1657 
1658  if (props) {
1659  moveDownOne(cubeToMosaic(props));
1660  }
1661  }
1662 
1663 
1664  void MosaicSceneWidget::moveToBottom() {
1665  DisplayProperties *props = qobject_cast<DisplayProperties *>(sender());
1666 
1667  if (props) {
1668  moveToBottom(cubeToMosaic(props));
1669  }
1670  }
1671 
1672 
1673  void MosaicSceneWidget::moveUpOne() {
1674  DisplayProperties *props = qobject_cast<DisplayProperties *>(sender());
1675 
1676  if (props) {
1677  moveUpOne(cubeToMosaic(props));
1678  }
1679  }
1680 
1681 
1682  void MosaicSceneWidget::moveToTop() {
1683  DisplayProperties *props = qobject_cast<DisplayProperties *>(sender());
1684 
1685  if (props) {
1686  moveToTop(cubeToMosaic(props));
1687  }
1688  }
1689 
1690 
1693  double MosaicSceneWidget::moveDownOne(MosaicSceneItem *item) {
1694  MosaicSceneItem *nextDown = getNextItem(item, false);
1695  double originalZ = item->zValue();
1696 
1697  if (nextDown) {
1698  double newZValue = nextDown->zValue() - 1;
1699  moveZ(item, newZValue, true);
1700  }
1701 
1702  return originalZ;
1703  }
1704 
1705 
1708  double MosaicSceneWidget::moveDownOne(Image *image) {
1709  return moveDownOne(cubeToMosaic(image));
1710  }
1711 
1712 
1715  QList<double> MosaicSceneWidget::moveDownOne(ImageList *images) {
1716  QList<double> results;
1717 
1718  foreach (Image *image, *images) {
1719  results.append(moveDownOne(image));
1720  }
1721 
1722  return results;
1723  }
1724 
1725 
1730  double MosaicSceneWidget::moveToBottom(MosaicSceneItem *item) {
1731  double originalZ = item->zValue();
1732  double minZ = minimumZ();
1733 
1734  if (originalZ != minZ) {
1735  // We know min-1 isn't already used
1736  int newZValue = qRound(minZ - 1);
1737  item->setZValue(newZValue);
1738 
1739  // Remove this if we enable the compress
1740  m_currentMinimumFootprintZ--;
1741  }
1742 
1743  return originalZ;
1744  }
1745 
1746 
1751  double MosaicSceneWidget::moveToBottom(Image *image) {
1752  return moveToBottom(cubeToMosaic(image));
1753  }
1754 
1755 
1760  QList<double> MosaicSceneWidget::moveToBottom(ImageList *images) {
1761  QList<double> results;
1762 
1763  foreach (Image *image, *images) {
1764  results.append(moveToBottom(image));
1765  }
1766 
1767  return results;
1768  }
1769 
1770 
1775  double MosaicSceneWidget::moveToTop(MosaicSceneItem *item) {
1776  double originalZ = item->zValue();
1777  double maxZ = maximumZ();
1778 
1779  if (originalZ != maxZ) {
1780  // We know max+1 isn't already used
1781  int newZValue = qRound(maxZ + 1);
1782  item->setZValue(newZValue);
1783 
1784  // Remove this if we enable the compress
1785  m_currentMaximumFootprintZ++;
1786  }
1787 
1788  // Compress... this makes this method have a time complexity of N instead of constant; there
1789  // isn't really a good justification for the slow down. I'm leaving this (working) code here
1790  // for reference and in case it's needed later.
1791  // foreach (MosaicSceneItem *otherItem, *m_mosaicSceneItems) {
1792  // double otherItemZ = otherItem->zValue();
1793  // if (otherItemZ > originalZ) {
1794  // otherItem->setZValue(otherItemZ - 1.0);
1795  // }
1796  // }
1797 
1798  return originalZ;
1799  }
1800 
1801 
1806  double MosaicSceneWidget::moveToTop(Image *image) {
1807  return moveToTop(cubeToMosaic(image));
1808  }
1809 
1810 
1815  QList<double> MosaicSceneWidget::moveToTop(ImageList *images) {
1816  QList<double> results;
1817 // qDebug() << "moveToTop( list...count=" << images->count() << ")";
1818 // printZ(m_mosaicSceneItems);
1819 
1820  foreach (Image *image, *images) {
1821  results.append(moveToTop(image));
1822  }
1823 
1824 
1825 // printZ(m_mosaicSceneItems);
1826  return results;
1827  }
1828 
1829 
1832  double MosaicSceneWidget::moveUpOne(MosaicSceneItem *item) {
1833  MosaicSceneItem *nextUp = getNextItem(item, true);
1834  double originalZ = item->zValue();
1835 
1836  if (nextUp) {
1837  double newZValue = nextUp->zValue() + 1;
1838  moveZ(item, newZValue, true);
1839  }
1840 
1841  return originalZ;
1842  }
1843 
1844 
1847  double MosaicSceneWidget::moveUpOne(Image *image) {
1848  return moveUpOne(cubeToMosaic(image));
1849  }
1850 
1851 
1854  QList<double> MosaicSceneWidget::moveUpOne(ImageList *images) {
1855  QList<double> results;
1856 
1857  foreach (Image *image, *images) {
1858  results.append(moveUpOne(image));
1859  }
1860 
1861  return results;
1862  }
1863 
1864 
1880  double MosaicSceneWidget::moveZ(MosaicSceneItem *sceneItem, double newZ,
1881  bool newZValueMightExist) {
1882  double originalZ = sceneItem->zValue();
1883 
1884  if (newZValueMightExist) {
1885  // Adjust items between original and new position, recalculate min/max - time complexity=N
1886  m_currentMinimumFootprintZ = 0.0;
1887  m_currentMaximumFootprintZ = 0.0;
1888 
1889  foreach (MosaicSceneItem *otherItem, *m_mosaicSceneItems) {
1890  double otherItemOrigZ = otherItem->zValue();
1891  double otherItemNewZ = otherItemOrigZ;
1892 
1893  // Moving downwards (new Z is lower than current Z) and item is in the middle
1894  if (originalZ > newZ && otherItemOrigZ >= newZ && otherItemOrigZ < originalZ) {
1895  otherItemNewZ = otherItemOrigZ + 1;
1896  }
1897  // Moving upwards (new Z is higher than current Z) and item is in the middle
1898  else if (originalZ < newZ && otherItemOrigZ <= newZ && otherItemOrigZ > originalZ) {
1899  otherItemNewZ = otherItemOrigZ - 1;
1900  }
1901 
1902  m_currentMinimumFootprintZ = qMin(m_currentMinimumFootprintZ, otherItemNewZ);
1903  m_currentMaximumFootprintZ = qMax(m_currentMaximumFootprintZ, otherItemNewZ);
1904  otherItem->setZValue(otherItemNewZ);
1905  }
1906  }
1907 
1908  sceneItem->setZValue(newZ);
1909 
1910  if (!newZValueMightExist) {
1911  // If we moved the max or min item, adjust the max down or min up respectively
1912  if (originalZ == maximumZ() && newZ < originalZ) {
1913  m_currentMaximumFootprintZ--;
1914  }
1915  else if (originalZ == minimumZ() && newZ > originalZ) {
1916  m_currentMinimumFootprintZ++;
1917  }
1918  }
1919 
1920  return originalZ;
1921  }
1922 
1923 
1924  double MosaicSceneWidget::moveZ(Image *image, double newZ,
1925  bool newZValueMightExist) {
1926  return moveZ(cubeToMosaic(image), newZ, newZValueMightExist);
1927  }
1928 
1929 
1930  void MosaicSceneWidget::fitInView() {
1931  if (m_userToolControl) {
1932  QRectF boundingBox;
1933 
1934  DisplayProperties *props = qobject_cast<DisplayProperties *>(sender());
1935 
1936  if (props) {
1937  MosaicSceneItem *item = cubeToMosaic(props);
1938  boundingBox = item->boundingRect();
1939  }
1940  else {
1941  QAction *action = qobject_cast<QAction *>(sender());
1942 
1943  if (action) {
1944  ImageList *images = action->data().value<ImageList *>();
1945 
1946  foreach (Image *image, *images) {
1947  ASSERT(cubeToMosaic(image));
1948  boundingBox = boundingBox.united(cubeToMosaic(image)->boundingRect());
1949  }
1950  }
1951  }
1952 
1953  if (!boundingBox.isNull()) {
1954  double xPadding = boundingBox.width() * 0.10;
1955  double yPadding = boundingBox.height() * 0.10;
1956 
1957  boundingBox.setLeft(boundingBox.left() - xPadding);
1958  boundingBox.setRight(boundingBox.right() + xPadding);
1959 
1960  boundingBox.setTop(boundingBox.top() - yPadding);
1961  boundingBox.setBottom(boundingBox.bottom() + yPadding);
1962 
1963  getView()->fitInView(boundingBox, Qt::KeepAspectRatio);
1964  getView()->centerOn(boundingBox.center());
1965  }
1966  }
1967  }
1968 
1969 
1970  void MosaicSceneWidget::onSelectionChanged() {
1971  if (!m_blockingSelectionChanged) {
1972  if (!m_queuedSelectionChanged) {
1973  emit queueSelectionChanged();
1974  m_queuedSelectionChanged = true;
1975  }
1976  else {
1977  m_shouldRequeueSelectionChanged = true;
1978  }
1979  }
1980  }
1981 
1982 
1983  void MosaicSceneWidget::onQueuedSelectionChanged() {
1984  m_queuedSelectionChanged = false;
1985 
1986  if (m_shouldRequeueSelectionChanged) {
1987  m_shouldRequeueSelectionChanged = false;
1988  onSelectionChanged();
1989  }
1990  else {
1991  foreach(MosaicSceneItem *mosaicSceneItem, *m_mosaicSceneItems) {
1992  mosaicSceneItem->updateSelection(true);
1993  }
1994  }
1995  }
1996 
1997 
2000  MosaicSceneItem *nextZValueItem = NULL;
2001  MosaicSceneItem *mosaicSceneItem;
2002 
2003  foreach(mosaicSceneItem, *m_mosaicSceneItems) {
2004  if (mosaicSceneItem != item &&
2005  mosaicSceneItem->boundingRect().intersects(item->boundingRect())) {
2006  // Does this item qualify as above or below at all?
2007  if ( (up && mosaicSceneItem->zValue() > item->zValue()) ||
2008  (!up && mosaicSceneItem->zValue() < item->zValue())) {
2009  // It is in the correct direction, set the initial guess if we don't
2010  // have one or test if it's better
2011  if (!nextZValueItem) {
2012  nextZValueItem = mosaicSceneItem;
2013  }
2014  else {
2015  // We know it qualifies, we want to know if it's closer than
2016  // nextZValueItem
2017  if ((up && mosaicSceneItem->zValue() < nextZValueItem->zValue()) ||
2018  (!up && mosaicSceneItem->zValue() > nextZValueItem->zValue())) {
2019  nextZValueItem = mosaicSceneItem;
2020  }
2021  }
2022  }
2023  }
2024  }
2025 
2026  return nextZValueItem;
2027  }
2028 
2029 
2030  bool MosaicSceneWidget::zOrderGreaterThan(MosaicSceneItem *first,
2031  MosaicSceneItem *second) {
2032  return first->zValue() > second->zValue();
2033  }
2034 
2035 
2036  MosaicSceneWidget::XmlHandler::XmlHandler(MosaicSceneWidget *scene) {
2037  m_scene = scene;
2038  m_scrollBarXValue = -1;
2039  m_scrollBarYValue = -1;
2040  m_imagesToAdd = NULL;
2041 
2042  m_imagesToAdd = new ImageList;
2043  }
2044 
2045 
2046  MosaicSceneWidget::XmlHandler::~XmlHandler() {
2047  delete m_imagesToAdd;
2048  m_imagesToAdd = NULL;
2049  }
2050 
2051 
2052  bool MosaicSceneWidget::XmlHandler::startElement(const QString &namespaceURI,
2053  const QString &localName, const QString &qName, const QXmlAttributes &atts) {
2054  bool result = XmlStackedHandler::startElement(namespaceURI, localName, qName, atts);
2055 
2056  m_characterData = "";
2057 
2058  if (result) {
2059  if (localName == "image" && m_scene->m_directory) {
2060  QString id = atts.value("id");
2061  double zValue = atts.value("zValue").toDouble();
2062  Image *image = m_scene->m_directory->project()->image(id);
2063  if (image) {
2064  m_imagesToAdd->append(image);
2065  m_imageZValues.append(zValue);
2066 // m_scene->cubeToMosaic(image)->setZValue(zValue);
2067  }
2068  }
2069  else if (localName == "viewTransform") {
2070  m_scrollBarXValue = atts.value("scrollBarXValue").toInt();
2071  m_scrollBarYValue = atts.value("scrollBarYValue").toInt();
2072  }
2073  }
2074 
2075  return result;
2076  }
2077 
2078 
2079  bool MosaicSceneWidget::XmlHandler::characters(const QString &ch) {
2080  bool result = XmlStackedHandler::characters(ch);
2081 
2082  if (result) {
2083  m_characterData += ch;
2084  }
2085 
2086  return result;
2087  }
2088 
2089 
2090  bool MosaicSceneWidget::XmlHandler::endElement(const QString &namespaceURI,
2091  const QString &localName, const QString &qName) {
2092  bool result = XmlStackedHandler::endElement(namespaceURI, localName, qName);
2093 
2094  if (result) {
2095  if (localName == "projection") {
2096  std::stringstream strStream(m_characterData.toStdString());
2097  PvlGroup mappingGroup;
2098  strStream >> mappingGroup;
2099  m_scene->setProjection(mappingGroup);
2100  }
2101  else if (localName == "viewTransform") {
2102  QByteArray hexValues(m_characterData.toAscii());
2103  QDataStream transformStream(QByteArray::fromHex(hexValues));
2104 
2105  QTransform viewTransform;
2106  transformStream >> viewTransform;
2107  m_scene->getView()->show();
2108  QCoreApplication::processEvents();
2109  m_scene->getView()->setTransform(viewTransform);
2110  m_scene->getView()->horizontalScrollBar()->setValue(m_scrollBarXValue);
2111  m_scene->getView()->verticalScrollBar()->setValue(m_scrollBarYValue);
2112  }
2113  else if (localName == "toolData") {
2114  PvlObject toolSettings;
2115  std::stringstream strStream(m_characterData.toStdString());
2116  strStream >> toolSettings;
2117 
2118  foreach (MosaicTool *tool, *m_scene->m_tools) {
2119  if (tool->projectPvlObjectName() == toolSettings.name()) {
2120  tool->fromPvl(toolSettings);
2121  }
2122  }
2123  }
2124  else if (localName == "images" && m_imagesToAdd->count()) {
2125  ASSERT(m_imagesToAdd->count() == m_imageZValues.count());
2126  m_scene->addImages(*m_imagesToAdd);
2127 
2128  for (int i = 0; i < m_imageZValues.count(); i++) {
2129  m_scene->cubeToMosaic(m_imagesToAdd->at(i))->setZValue(m_imageZValues[i]);
2130  m_scene->m_currentMinimumFootprintZ = qMin(m_scene->m_currentMinimumFootprintZ,
2131  m_imageZValues[i]);
2132  m_scene->m_currentMaximumFootprintZ = qMax(m_scene->m_currentMaximumFootprintZ,
2133  m_imageZValues[i]);
2134  }
2135  }
2136  }
2137 
2138  m_characterData = "";
2139 
2140  return result;
2141  }
2142 }