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