1#include "MosaicSceneWidget.h" 
    6#include <QGraphicsSceneContextMenuEvent> 
   27#include "GraphicsView.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" 
   49#include "Projection.h" 
   50#include "ProjectionConfigDialog.h" 
   51#include "ProjectionFactory.h" 
   58#include "XmlStackedHandlerReader.h" 
   65                                       bool internalizeToolBarsAndProgress, 
Directory *directory,
 
   67    m_projectImageZOrders = NULL;
 
   68    m_projectViewTransform = NULL;
 
   69    m_directory = directory;
 
   71    m_mosaicSceneItems = 
new QList<MosaicSceneItem *>;
 
   87    m_quickMapAction = NULL;
 
   89    m_cubesSelectable = 
true;
 
   90    m_customRubberBandEnabled = 
false;
 
   91    m_customRubberBand = NULL;
 
   92    m_rubberBandOrigin = NULL;
 
   94    m_blockingSelectionChanged = 
false;
 
   95    m_queuedSelectionChanged = 
false;
 
   96    m_shouldRequeueSelectionChanged = 
false;
 
   98    m_userToolControl = 
false;
 
   99    m_ownProjection = 
false;
 
  102    m_progress->setVisible(
false);
 
  104    QGridLayout * sceneLayout = 
new QGridLayout;
 
  105    sceneLayout->setContentsMargins(0, 0, 0, 0);
 
  106    setLayout(sceneLayout);
 
  109    if (!status && internalizeToolBarsAndProgress)
 
  110      status = 
new QStatusBar;
 
  113    m_tools = 
new QList<MosaicTool *>;
 
  118    m_tools->append(cnetTool);
 
  122    connect(cnetTool, SIGNAL(modifyControlPoint(
ControlPoint *)),
 
  125    connect(cnetTool, SIGNAL(deleteControlPoint(
ControlPoint *)),
 
  128    connect(cnetTool, SIGNAL(createControlPoint(
double, 
double)),
 
  129            this, SIGNAL(createControlPoint(
double, 
double)));
 
  132    connect(
this, SIGNAL(cnetModified()), cnetTool, SLOT(rebuildPointGraphics()));
 
  140    m_tools->at(0)->activate(
true);
 
  144      if (internalizeToolBarsAndProgress) {
 
  159        QHBoxLayout *horizontalToolBarsLayout = 
new QHBoxLayout;
 
  161        m_permToolbar = 
new QToolBar(
"Standard Tools");
 
  162        m_permToolbar->setWhatsThis(
"This area contains options that are always present in the " 
  164        horizontalToolBarsLayout->addWidget(m_permToolbar);
 
  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);
 
  172        sceneLayout->addLayout(horizontalToolBarsLayout, 0, 0, 1, 2);
 
  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);
 
  182        QHBoxLayout *horizontalStatusLayout = 
new QHBoxLayout;
 
  183        horizontalStatusLayout->addWidget(m_progress);
 
  184        horizontalStatusLayout->addStretch();
 
  185        horizontalStatusLayout->addWidget(status);
 
  187        sceneLayout->addLayout(horizontalStatusLayout, 2, 0, 1, 2);
 
  189        addToPermanent(m_permToolbar);
 
  190        m_permToolbar->addSeparator();
 
  192        addTo(m_activeToolbar);
 
  199      m_userToolControl = 
true;
 
  201      setWhatsThis(
"This is the mosaic scene. The opened cubes will be " 
  202          "shown here. You can fully interact with the files shown here.");
 
  204      getView()->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
 
  205      getView()->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
 
  207      getView()->enableResizeZooming(
false);
 
  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()));
 
  222      getView()->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
 
  223      getView()->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
 
  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.");
 
  233    m_currentMinimumFootprintZ = 0;
 
  234    m_currentMaximumFootprintZ = 0;
 
  236    connect(getScene(), SIGNAL(selectionChanged()),
 
  237            this, SLOT(onSelectionChanged()));
 
  240    connect(
this, SIGNAL(queueSelectionChanged()),
 
  241            this, SLOT(onQueuedSelectionChanged()), Qt::QueuedConnection);
 
 
  244  MosaicSceneWidget::~MosaicSceneWidget() {
 
  245    m_outlineRect = NULL; 
 
  262    delete m_projectImageZOrders;
 
  263    m_projectImageZOrders = NULL;
 
  265    delete m_projectViewTransform;
 
  266    m_projectViewTransform = NULL;
 
  274    if (!mapping.hasKeyword(
"EquatorialRadius")) {
 
  276      tmp.findGroup(
"Mapping") += radii[
"EquatorialRadius"];
 
  277      tmp.findGroup(
"Mapping") += radii[
"PolarRadius"];
 
  281    m_ownProjection = 
true;
 
  292      PvlKeyword projectionKeyword = mapping.findKeyword(
"ProjectionName");
 
  293      QString projName = projectionKeyword[0];
 
  294      m_mapButton->setText(tr(
"View/Edit %1 Projection").arg(projName));
 
  303    if (old && m_ownProjection) {
 
  308    m_ownProjection = 
false;
 
 
  313  void MosaicSceneWidget::setOutlineRect(QRectF outline) {
 
  314    if (outline.united(getView()->sceneRect()) != getView()->sceneRect())
 
  317    if (!m_outlineRect) {
 
  318      m_outlineRect = getScene()->addRect(outline,
 
  321      m_outlineRect->setZValue(DBL_MAX);
 
  324      m_outlineRect->setRect(outline);
 
  327    if (!m_userToolControl)
 
  332  PvlGroup MosaicSceneWidget::createInitialProjection(
 
  334    Projection *proj = NULL;
 
  335    Cube *cube = image->cube();
 
  336    Pvl *label = cube->label();
 
  340      return proj->Mapping();
 
  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");
 
  356        Camera * cam = cube->camera();
 
  360        mappingGrp += PvlKeyword(
"TargetName", cam->target()->name());
 
  361        mappingGrp += PvlKeyword(
"EquatorialRadius", 
toString(radii[0].meters()),
 
  363        mappingGrp += PvlKeyword(
"PolarRadius", 
toString(radii[2].meters()),
 
  367      catch (IException &) {
 
  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);
 
  392      PvlKeyword projectionKeyword =
 
  394      QString projName = projectionKeyword[0];
 
  395      m_mapButton->setText(projName);
 
  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()));
 
  406    perm->addWidget(m_mapButton);
 
  407    perm->addAction(m_quickMapAction);
 
  411  void MosaicSceneWidget::addTo(
QToolBar *toolbar) {
 
  413    foreach(tool, *m_tools) {
 
  414      tool->addTo(toolbar);
 
  419  void MosaicSceneWidget::addTo(
QMenu *menu) {
 
  421    foreach(tool, *m_tools) {
 
  427  void MosaicSceneWidget::addTo(ToolPad *toolPad) {
 
  429    foreach(tool, *m_tools) {
 
  430      tool->addTo(toolPad);
 
  442    bool handled = 
false;
 
  443    QList<QGraphicsItem *> selectedGraphicsItems = getScene()->selectedItems();
 
  444    QList<MosaicSceneItem *> selectedImageItems;
 
  446    foreach (
QGraphicsItem *graphicsItem, selectedGraphicsItems) {
 
  449      if (!sceneImageItem) {
 
  450        sceneImageItem = 
dynamic_cast<MosaicSceneItem *
>(graphicsItem->parentItem());
 
  453      if (sceneImageItem && sceneImageItem->image()) {
 
  454        selectedImageItems.append(sceneImageItem);
 
  459    if (selectedImageItems.count()) {
 
  463      title->setEnabled(
false);
 
  471        displayActs.append(NULL);
 
  476      foreach(displayAct, displayActs) {
 
  477        if (displayAct == NULL) {
 
  481          menu.addAction(displayAct);
 
  486      menu.exec(event->screenPos());
 
 
  494  void MosaicSceneWidget::enableRubberBand(
bool enable) {
 
  495    m_customRubberBandEnabled = enable;
 
  499  MosaicSceneItem *MosaicSceneWidget::cubeToMosaic(Image *image) {
 
  501      QString msg = tr(
"Can not find a NULL image in the mosaic");
 
  505    return cubeToMosaic(image->displayProperties());
 
  509  bool MosaicSceneWidget::blockSelectionChange(
bool block) {
 
  510    bool wasBlocking = m_blockingSelectionChanged;
 
  512    m_blockingSelectionChanged = block;
 
  523  PvlObject MosaicSceneWidget::toPvl()
 const {
 
  524    PvlObject output(
"MosaicScene");
 
  530      dataBuffer.open(QIODevice::ReadWrite);
 
  531      QDataStream transformStream(&dataBuffer);
 
  532      transformStream << getView()->transform();
 
  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;
 
  543      output += mosaicScenePosition;
 
  546      foreach(tool, *m_tools) {
 
  547        if (tool->projectPvlObjectName() != 
"") {
 
  548          PvlObject toolObj = tool->toPvl();
 
  549          toolObj.setName(tool->projectPvlObjectName());
 
  554      PvlObject zOrders(
"ZOrdering");
 
  555      foreach(MosaicSceneItem * mosaicSceneItem, *m_mosaicSceneItems) {
 
  556        PvlKeyword zValue(
"ZValue");
 
  557        zValue += mosaicSceneItem->image()->id();
 
  558        zValue += 
toString(mosaicSceneItem->zValue());
 
  566          "Cannot save a scene without a projection to a project file",
 
  584    foreach(tool, *m_tools) {
 
  585      if (tool->projectPvlObjectName() != 
"") {
 
  586        if (project.
hasObject(tool->projectPvlObjectName())) {
 
  588              project.
findObject(tool->projectPvlObjectName()));
 
  589          tool->fromPvl(toolSettings);
 
  596        delete m_projectImageZOrders;
 
  597        m_projectImageZOrders = NULL;
 
  598        m_projectImageZOrders = 
new QHash<QString, double>;
 
  600        for (
int zOrderIndex = 0;
 
  601             zOrderIndex < zOrders.keywords();
 
  603          const PvlKeyword &zOrder = zOrders[zOrderIndex];
 
  605          (*m_projectImageZOrders)[zOrder[0]] = 
toDouble(zOrder[1]);
 
  609      if (project.
hasObject(
"SceneVisiblePosition")) {
 
  613        delete m_projectViewTransform;
 
  614        m_projectViewTransform = 
new PvlObject(positionInfo);
 
 
  621    xmlReader->pushContentHandler(
new XmlHandler(
this));
 
  625  void MosaicSceneWidget::save(QXmlStreamWriter &stream, Project *, FileName )
 const {
 
  627      stream.writeStartElement(
"mosaicScene");
 
  629      stream.writeStartElement(
"projection");
 
  631      std::stringstream strStream;
 
  632      strStream << mapping;
 
  633      stream.writeCharacters(strStream.str().c_str());
 
  634      stream.writeEndElement();
 
  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();
 
  643      stream.writeEndElement();
 
  645      stream.writeStartElement(
"viewTransform");
 
  646      stream.writeAttribute(
"scrollBarXValue", 
toString(getView()->horizontalScrollBar()->value()));
 
  647      stream.writeAttribute(
"scrollBarYValue", 
toString(getView()->verticalScrollBar()->value()));
 
  649      dataBuffer.open(QIODevice::ReadWrite);
 
  650      QDataStream transformStream(&dataBuffer);
 
  651      transformStream << getView()->transform();
 
  653      stream.writeCharacters(dataBuffer.data().toHex());
 
  654      stream.writeEndElement();
 
  656      foreach(MosaicTool *tool, *m_tools) {
 
  657        QString projectPvlObjectName = tool->projectPvlObjectName();
 
  658        if (projectPvlObjectName != 
"") {
 
  659          PvlObject toolObj = tool->toPvl();
 
  660          toolObj.setName(projectPvlObjectName);
 
  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();
 
  671      stream.writeEndElement();
 
  676  QRectF MosaicSceneWidget::cubesBoundingRect()
 const {
 
  679    MosaicSceneItem * mosaicItem;
 
  680    foreach(mosaicItem, *m_mosaicSceneItems) {
 
  681      if (boundingRect.isEmpty())
 
  682        boundingRect = mosaicItem->boundingRect();
 
  684        boundingRect = boundingRect.united(mosaicItem->boundingRect());
 
  688      boundingRect = boundingRect.united(m_outlineRect->boundingRect());
 
  694  MosaicSceneItem *MosaicSceneWidget::cubeToMosaic(DisplayProperties *props) {
 
  696      QString msg = tr(
"Can not find a NULL Display Properties in the mosaic");
 
  700    return m_displayPropsToMosaicSceneItemMap[props];
 
  707    MosaicSceneItem *mosaicSceneItem;
 
  708    foreach(mosaicSceneItem, *m_mosaicSceneItems) {
 
  709      if (mosaicSceneItem->image())
 
  710        cubes.append(mosaicSceneItem->image()->fileName());
 
  717  Directory *MosaicSceneWidget::directory()
 const {
 
  722  ImageList MosaicSceneWidget::images() {
 
  725    MosaicSceneItem *mosaicSceneItem;
 
  726    foreach(mosaicSceneItem, *m_mosaicSceneItems) {
 
  727      if (mosaicSceneItem->image())
 
  728        images.
append(mosaicSceneItem->image());
 
  742    QList<QGraphicsItem *> selectedGraphicsItems = getScene()->selectedItems();
 
  743    QList<MosaicSceneItem *> selectedImageItems;
 
  746    foreach (
QGraphicsItem *graphicsItem, selectedGraphicsItems) {
 
  749      if (!sceneImageItem) {
 
  750        sceneImageItem = 
dynamic_cast<MosaicSceneItem *
>(graphicsItem->parentItem());
 
  753      if (sceneImageItem && sceneImageItem->image()) {
 
  754        selectedImageItems.append(sceneImageItem);
 
 
  777  QList<QAction *> MosaicSceneWidget::getExportActions() {
 
  778    QList<QAction *> exportActs;
 
  785    saveList->setText(
"Save Entire Cube List (ordered by &view)...");
 
  786    connect(saveList, SIGNAL(triggered()), 
this, SLOT(saveList()));
 
  789    exportActs.append(saveList);
 
  795  QList<QAction *> MosaicSceneWidget::getViewActions() {
 
  796    QList<QAction *> viewActs;
 
  798    foreach(MosaicTool *tool, *m_tools) {
 
  799      QList<QAction *> toolViewActs = tool->getViewActions();
 
  800      viewActs.append(toolViewActs);
 
  811    QList<QAction *> results;
 
  812    bool allImagesInView = !images->isEmpty();
 
  814    foreach (
Image *image, *images) {
 
  815      allImagesInView = allImagesInView && (cubeToMosaic(image) != NULL);
 
  818    if (allImagesInView) {
 
  821      moveToTopAct->setData(images);
 
  822      results.append(moveToTopAct);
 
  826      moveUpOneAct->setData(images);
 
  827      results.append(moveUpOneAct);
 
  831      moveToBottomAct->setData(images);
 
  832      results.append(moveToBottomAct);
 
  836      moveDownOneAct->setData(images);
 
  837      results.append(moveDownOneAct);
 
  839      results.append(NULL);
 
  842      zoomFitAct->setData(qVariantFromValue(images));
 
  843      connect(zoomFitAct, SIGNAL(triggered()), 
this, SLOT(fitInView()));
 
  844      results.append(zoomFitAct);
 
 
  850  bool MosaicSceneWidget::isControlNetToolActive() {
 
  855        if (cnTool->isActive()) 
return true;
 
  862  QWidget * MosaicSceneWidget::getControlNetHelp(
QWidget *cnetToolContainer) {
 
  863    QScrollArea *cnetHelpWidgetScrollArea = 
new QScrollArea;
 
  867    QVBoxLayout *cnetHelpLayout = 
new QVBoxLayout;
 
  868    cnetHelpWidget->setLayout(cnetHelpLayout);
 
  870    QLabel *title = 
new QLabel(
"<h2>Control Networks</h2>");
 
  871    cnetHelpLayout->addWidget(title);
 
  873    QPixmap previewPixmap;
 
  875    if (cnetToolContainer) {
 
  876      previewPixmap = cnetToolContainer->grab().scaled(
 
  877          QSize(500, 200), Qt::KeepAspectRatio, Qt::SmoothTransformation);
 
  880      ToolPad tmpToolPad(
"Example Tool Pad", NULL);
 
  881      MosaicControlNetTool tmpTool(NULL);
 
  882      tmpTool.addTo(&tmpToolPad);
 
  884      tmpToolPad.resize(QSize(32, 32));
 
  886      previewPixmap = tmpToolPad.grab();
 
  889    QLabel *previewWrapper = 
new QLabel;
 
  890    previewWrapper->setPixmap(previewPixmap);
 
  891    cnetHelpLayout->addWidget(previewWrapper);
 
  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>" 
  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);
 
  930    cnetHelpWidgetScrollArea->setWidget(cnetHelpWidget);
 
  932    return cnetHelpWidgetScrollArea;
 
  936  QWidget * MosaicSceneWidget::getGridHelp(
QWidget *gridToolContainer) {
 
  937    QScrollArea *gridHelpWidgetScrollArea = 
new QScrollArea;
 
  941    QVBoxLayout *gridHelpLayout = 
new QVBoxLayout;
 
  942    gridHelpWidget->setLayout(gridHelpLayout);
 
  944    QLabel *title = 
new QLabel(
"<h2>Map Grid Tool</h2>");
 
  945    gridHelpLayout->addWidget(title);
 
  947    QPixmap previewPixmap;
 
  949    if (gridToolContainer) {
 
  950      previewPixmap = gridToolContainer->grab().scaled(
 
  951          QSize(500, 200), Qt::KeepAspectRatio, Qt::SmoothTransformation);
 
  954      ToolPad tmpToolPad(
"Example Tool Pad", NULL);
 
  955      MosaicGridTool tmpTool(NULL);
 
  956      tmpTool.addTo(&tmpToolPad);
 
  958      tmpToolPad.resize(QSize(32, 32));
 
  960      previewPixmap = tmpToolPad.grab();
 
  963    QLabel *previewWrapper = 
new QLabel;
 
  964    previewWrapper->setPixmap(previewPixmap);
 
  965    gridHelpLayout->addWidget(previewWrapper);
 
  967    QLabel *overview = 
new QLabel(
"Superimpose a map grid over the area of " 
  968        "displayed footprints in the 'mosaic scene.'" 
  971          "<li>The Map Grid Tool is activated by selecting the 'cross-hatch' " 
  972              "icon or typing 'g' at the keyboard." 
  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." 
  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 " 
  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." 
  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." 
  995        "<strong>Options:</strong>" 
  997        "<li>The 'Show Grid' option draws (checked) or clears (unchecked) the grid." 
  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." 
 1003        "<li>The expected units for each entry are displayed to the right of the " 
 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 " 
 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." 
 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." 
 1019    overview->setWordWrap(
true);
 
 1020    gridHelpLayout->addWidget(overview);
 
 1022    gridHelpWidgetScrollArea->setWidget(gridHelpWidget);
 
 1024    return gridHelpWidgetScrollArea;
 
 1028  QWidget * MosaicSceneWidget::getLongHelp(
QWidget *sceneContainer) {
 
 1029    QScrollArea *longHelpWidgetScrollArea = 
new QScrollArea;
 
 1033    QVBoxLayout *longHelpLayout = 
new QVBoxLayout;
 
 1034    longHelpWidget->setLayout(longHelpLayout);
 
 1036    QLabel *title = 
new QLabel(
"<h2>Mosaic Scene</h2>");
 
 1037    longHelpLayout->addWidget(title);
 
 1039    if (sceneContainer) {
 
 1040      QPixmap previewPixmap = sceneContainer->grab().scaled(
 
 1041          QSize(500, 200), Qt::KeepAspectRatio, Qt::SmoothTransformation);
 
 1043      QLabel *previewWrapper = 
new QLabel;
 
 1044      previewWrapper->setPixmap(previewPixmap);
 
 1045      longHelpLayout->addWidget(previewWrapper);
 
 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." 
 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>" 
 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 " 
 1069    overview->setWordWrap(
true);
 
 1070    longHelpLayout->addWidget(overview);
 
 1072    longHelpWidgetScrollArea->setWidget(longHelpWidget);
 
 1074    return longHelpWidgetScrollArea;
 
 1079    QScrollArea *mapHelpWidgetScrollArea = 
new QScrollArea;
 
 1083    QVBoxLayout *mapHelpLayout = 
new QVBoxLayout;
 
 1084    mapHelpWidget->setLayout(mapHelpLayout);
 
 1086    QLabel *title = 
new QLabel(tr(
"<h2>Map File</h2>"));
 
 1087    mapHelpLayout->addWidget(title);
 
 1090      QPixmap previewPixmap = mapContainer->grab().scaled(
 
 1091          QSize(500, 200), Qt::KeepAspectRatio, Qt::SmoothTransformation);
 
 1093      QLabel *previewWrapper = 
new QLabel;
 
 1094      previewWrapper->setPixmap(previewPixmap);
 
 1095      mapHelpLayout->addWidget(previewWrapper);
 
 1098    QLabel *overviewMapIcon = 
new QLabel;
 
 1100    overviewMapIcon->setPixmap(
 
 1101        QIcon(FileName(
"$ISISROOT/appdata/images/icons/ographic.png").expanded()).pixmap(32, 32));
 
 1102    mapHelpLayout->addWidget(overviewMapIcon);
 
 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)."));
 
 1114    defaultMapFile->setWordWrap(
true);
 
 1115    mapHelpLayout->addWidget(defaultMapFile);
 
 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()));
 
 1127    userDefinedMapFileOverview->setWordWrap(
true);
 
 1128    mapHelpLayout->addWidget(userDefinedMapFileOverview);
 
 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."));
 
 1134    userDefinedMapFileQuickLoad->setWordWrap(
true);
 
 1135    mapHelpLayout->addWidget(userDefinedMapFileQuickLoad);
 
 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."));
 
 1141    userDefinedMapFileAnyTime->setWordWrap(
true);
 
 1142    mapHelpLayout->addWidget(userDefinedMapFileAnyTime);
 
 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));
 
 1157    preparingMapFile->setOpenExternalLinks(
true);
 
 1158    preparingMapFile->setWordWrap(
true);
 
 1159    mapHelpLayout->addWidget(preparingMapFile);
 
 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."));
 
 1168    mapFileDisplayResults->setWordWrap(
true);
 
 1169    mapHelpLayout->addWidget(mapFileDisplayResults);
 
 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)."));
 
 1178    editingMapFileOverview->setWordWrap(
true);
 
 1179    mapHelpLayout->addWidget(editingMapFileOverview);
 
 1181    QLabel *saveMapFileToDiskBullet = 
new QLabel(tr(
 
 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 " 
 1191    saveMapFileToDiskBullet->setWordWrap(
true);
 
 1192    mapHelpLayout->addWidget(saveMapFileToDiskBullet);
 
 1194    QLabel *mapFileValidityBullet = 
new QLabel(tr(
 
 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 " 
 1206    mapFileValidityBullet->setWordWrap(
true);
 
 1207    mapHelpLayout->addWidget(mapFileValidityBullet);
 
 1209    QLabel *mapFileCommentsBullet = 
new QLabel(tr(
 
 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/>" 
 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\"." 
 1225    mapFileCommentsBullet->setWordWrap(
true);
 
 1226    mapHelpLayout->addWidget(mapFileCommentsBullet);
 
 1228    mapHelpWidgetScrollArea->setWidget(mapHelpWidget);
 
 1230    return mapHelpWidgetScrollArea;
 
 1234  QWidget * MosaicSceneWidget::getPreviewHelp(
QWidget *worldViewContainer) {
 
 1235    QScrollArea *previewHelpWidgetScrollArea = 
new QScrollArea;
 
 1239    QVBoxLayout *previewHelpLayout = 
new QVBoxLayout;
 
 1240    previewHelpWidget->setLayout(previewHelpLayout);
 
 1242    QLabel *title = 
new QLabel(
"<h2>Mosaic World View</h2>");
 
 1243    previewHelpLayout->addWidget(title);
 
 1245    if (worldViewContainer) {
 
 1246      QPixmap previewPixmap = worldViewContainer->grab().scaled(
 
 1247          QSize(500, 200), Qt::KeepAspectRatio, Qt::SmoothTransformation);
 
 1249      QLabel *previewWrapper = 
new QLabel;
 
 1250      previewWrapper->setPixmap(previewPixmap);
 
 1251      previewHelpLayout->addWidget(previewWrapper);
 
 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);
 
 1261    previewHelpWidgetScrollArea->setWidget(previewHelpWidget);
 
 1263    return previewHelpWidgetScrollArea;
 
 1267  MosaicSceneItem *MosaicSceneWidget::addImage(Image *image) {
 
 1269      setProjection(createInitialProjection(image), *image->cube()->label());
 
 1272    MosaicSceneItem *mosItem = NULL;
 
 1275    if (!cubeToMosaic(image)) {
 
 1276      mosItem = 
new MosaicSceneItem(image, 
this);
 
 1278      connect(mosItem, SIGNAL(changed(
const QList<QRectF> &)),
 
 1280      connect(mosItem, SIGNAL(mosaicCubeClosed(Image *)),
 
 1281              this, SIGNAL(mosCubeClosed(Image *)));
 
 1285      if (m_projectImageZOrders && m_projectImageZOrders->contains(image->id())) {
 
 1286        double zOrder = m_projectImageZOrders->value(image->id());
 
 1287        m_projectImageZOrders->remove(image->id());
 
 1289        foreach (MosaicSceneItem *mosaicItem, *m_mosaicSceneItems) {
 
 1290          if (mosaicItem->zValue() == zOrder) {
 
 1291            mosaicItem->setZValue(maximumZ() + 1);
 
 1292            m_currentMaximumFootprintZ = maximumZ() + 1;
 
 1296        m_currentMaximumFootprintZ = qMax(zOrder, maximumZ());
 
 1297        mosItem->setZValue(zOrder);
 
 1300        mosItem->setZValue(maximumZ() + 1);
 
 1301        m_currentMaximumFootprintZ = maximumZ() + 1;
 
 1304      getScene()->addItem(mosItem);
 
 1305      m_mosaicSceneItems->append(mosItem);
 
 1306      m_displayPropsToMosaicSceneItemMap[image->displayProperties()] = mosItem;
 
 1308      connect(mosItem, SIGNAL(destroyed(
QObject *)),
 
 1309              this, SLOT(removeMosItem(
QObject *)));
 
 1311      ImageDisplayProperties *prop = image->displayProperties();
 
 1312      connect(prop, SIGNAL(moveDownOne()),
 
 1313              this, SLOT(moveDownOne()));
 
 1316      connect(prop, SIGNAL(moveUpOne()),
 
 1317              this, SLOT(moveUpOne()));
 
 1320      connect(prop, SIGNAL(zoomFit()),
 
 1321              this, SLOT(fitInView()));
 
 1328  double MosaicSceneWidget::maximumZ() {
 
 1329    return m_currentMaximumFootprintZ;
 
 1333  double MosaicSceneWidget::minimumZ() {
 
 1334    return m_currentMinimumFootprintZ;
 
 1337  void MosaicSceneWidget::recalcSceneRect() {
 
 1339      double minX, minY, maxX, maxY;
 
 1342      QRectF projRect(minX, -maxY, maxX - minX, maxY - minY);
 
 1343      QRectF cubesBounding = cubesBoundingRect();
 
 1345      QRectF bounding = projRect.united(cubesBounding);
 
 1347      if (m_outlineRect && m_outlineRect->isVisible())
 
 1348        bounding = bounding.united(m_outlineRect->boundingRect());
 
 1350      getView()->setSceneRect(bounding);
 
 1354  void MosaicSceneWidget::addImages(ImageList images) {
 
 1355    if (m_userToolControl)
 
 1356      m_progress->
setText(
"Loading primary scene");
 
 1358      m_progress->
setText(
"Loading secondary scene");
 
 1360    m_progress->setRange(0, images.size() - 1);
 
 1361    m_progress->setValue(0);
 
 1362    m_progress->setVisible(
true);
 
 1364    foreach(Image *image, images) {
 
 1368      catch (IException &e) {
 
 1372      m_progress->setValue(m_progress->value() + 1);
 
 1377    if (m_projectViewTransform) {
 
 1378      PvlObject &positionInfo = *m_projectViewTransform;
 
 1379      QByteArray hexValues(positionInfo[
"ViewTransform"][0].toLatin1());
 
 1380      QDataStream transformStream(QByteArray::fromHex(hexValues));
 
 1382      QTransform viewTransform;
 
 1383      transformStream >> viewTransform;
 
 1384      getView()->setTransform(viewTransform);
 
 1386      QPoint projectScrollPos(
toInt(positionInfo[
"ScrollPosition"][0]),
 
 1387                              toInt(positionInfo[
"ScrollPosition"][1]));
 
 1389      getView()->horizontalScrollBar()->setValue(projectScrollPos.x());
 
 1390      getView()->verticalScrollBar()->setValue(projectScrollPos.y());
 
 1396    if (!m_projectImageZOrders || m_projectImageZOrders->isEmpty()) {
 
 1397      delete m_projectViewTransform;
 
 1398      m_projectViewTransform = NULL;
 
 1401    m_progress->setVisible(
false);
 
 1402    emit cubesChanged();
 
 1406  void MosaicSceneWidget::removeImages(ImageList images) {
 
 1409    foreach(Image *image, images) {
 
 1411        MosaicSceneItem *item = cubeToMosaic(image);
 
 1412        item->deleteLater();
 
 1413        removeMosItem(item);
 
 1415      catch (IException &e) {
 
 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;
 
 1434    if (QFileInfo(output).suffix().isEmpty()) {
 
 1435      output = output + 
".png";
 
 1438    QString format = QFileInfo(output).suffix();
 
 1439    QPixmap pm = getScene()->views().last()->grab();
 
 1441    std::string formatString = format.toStdString();
 
 1442    if (!pm.save(output, formatString.c_str())) {
 
 1443      QMessageBox::information(
this, 
"Error",
 
 1444                               "Unable to save [" + output + 
"]");
 
 
 1449  void MosaicSceneWidget::saveList() {
 
 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;
 
 1457    TextFile file(output, 
"overwrite");
 
 1459    QList<MosaicSceneItem *> sorted = *m_mosaicSceneItems;
 
 1460    std::sort(sorted.begin(), sorted.end(), zOrderGreaterThan);
 
 1463    foreach(sceneItem, sorted) {
 
 1464      file.PutLine( sceneItem->image()->fileName() );
 
 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));
 
 1475    emit cubesChanged();
 
 1484    QRectF sceneRect = cubesBoundingRect();
 
 1486    if (sceneRect.isEmpty())
 
 1489    double xPadding = sceneRect.width() * 0.10;
 
 1490    double yPadding = sceneRect.height() * 0.10;
 
 1492    sceneRect.adjust(-xPadding, -yPadding, xPadding, yPadding);
 
 1493    getView()->fitInView(sceneRect, Qt::KeepAspectRatio);
 
 
 1497  void MosaicSceneWidget::setCubesSelectable(
bool selectable) {
 
 1498    if (m_cubesSelectable != selectable) {
 
 1499      m_cubesSelectable = selectable;
 
 1502      foreach(mosaicSceneItem, *m_mosaicSceneItems) {
 
 1503        mosaicSceneItem->scenePropertiesChanged();
 
 1515    configDialog.exec();
 
 
 1519  void MosaicSceneWidget::quickConfigProjectionParameters() {
 
 1521    configDialog.setQuickConfig(
true);
 
 1522    configDialog.exec();
 
 1526  void MosaicSceneWidget::sendVisibleRectChanged() {
 
 1527    QPointF topLeft = getView()->mapToScene(0, 0);
 
 1528    QPointF bottomRight = getView()->mapToScene(
 
 1529        (
int)getView()->width(),
 
 1530        (
int)getView()->height());
 
 1532    QRectF visibleRect(topLeft, bottomRight);
 
 1533    emit visibleRectChanged(visibleRect);
 
 1537  bool MosaicSceneWidget::eventFilter(
QObject *obj, QEvent *event) {
 
 1538    bool stopProcessingEvent = 
true;
 
 1540    switch(event->type()) {
 
 1541      case QMouseEvent::GraphicsSceneMousePress: {
 
 1542        if (m_customRubberBandEnabled) {
 
 1544          if (!m_customRubberBand) {
 
 1545            m_customRubberBand = 
new QRubberBand(QRubberBand::Rectangle,
 
 1549          if (!m_rubberBandOrigin) {
 
 1550            m_rubberBandOrigin = 
new QPoint;
 
 1553          *m_rubberBandOrigin = getView()->mapFromScene(
 
 1554              ((QGraphicsSceneMouseEvent *)event)->scenePos());
 
 1555          m_customRubberBand->setGeometry(QRect(*m_rubberBandOrigin, QSize()));
 
 1556          m_customRubberBand->show();
 
 1559        emit mouseButtonPress(
 
 1560              ((QGraphicsSceneMouseEvent *)event)->scenePos(),
 
 1561              ((QGraphicsSceneMouseEvent *)event)->button());
 
 1562        stopProcessingEvent = 
false;
 
 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;
 
 1579          delete m_rubberBandOrigin;
 
 1580          m_rubberBandOrigin = NULL;
 
 1582          delete m_customRubberBand;
 
 1583          m_customRubberBand = NULL;
 
 1586        if (!signalEmitted) {
 
 1587          stopProcessingEvent = 
false;
 
 1588          emit mouseButtonRelease(
 
 1589                ((QGraphicsSceneMouseEvent *)event)->scenePos(),
 
 1590                ((QGraphicsSceneMouseEvent *)event)->button());
 
 1595      case QMouseEvent::GraphicsSceneMouseDoubleClick:
 
 1596        emit mouseDoubleClick(
 
 1597              ((QGraphicsSceneMouseEvent *)event)->scenePos());
 
 1598        stopProcessingEvent = 
false;
 
 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);
 
 1607          QRect rubberBandRect =
 
 1608              QRect(*m_rubberBandOrigin, screenPos).normalized();
 
 1610          m_customRubberBand->setGeometry(rubberBandRect);
 
 1613          stopProcessingEvent = 
false;
 
 1617              ((QGraphicsSceneMouseEvent *)event)->scenePos());
 
 1620      case QEvent::GraphicsSceneWheel:
 
 1622              ((QGraphicsSceneWheelEvent *)event)->scenePos(),
 
 1623              ((QGraphicsSceneWheelEvent *)event)->delta());
 
 1625        stopProcessingEvent = 
true;
 
 1628      case QMouseEvent::Enter:
 
 1630        stopProcessingEvent = 
false;
 
 1633      case QMouseEvent::Leave:
 
 1635        stopProcessingEvent = 
false;
 
 1638      case QEvent::GraphicsSceneHelp: {
 
 1640        bool toolTipFound = 
false;
 
 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;
 
 1655          stopProcessingEvent = 
true;
 
 1657              ((QGraphicsSceneHelpEvent*)event)->screenPos(),
 
 1664        stopProcessingEvent = 
false;
 
 1668    return stopProcessingEvent;
 
 1679    if (m_mosaicSceneItems->size() == 0)
 
 1682    if (m_userToolControl)
 
 1683      m_progress->
setText(
"Reprojecting primary scene");
 
 1685      m_progress->
setText(
"Reprojecting secondary scene");
 
 1688    int reprojectsPerUpdate = qMax(1, m_mosaicSceneItems->size() / 20);
 
 1690    m_progress->setRange(0,
 
 1691        (m_mosaicSceneItems->size() - 1) / reprojectsPerUpdate + 1);
 
 1692    m_progress->setValue(0);
 
 1693    m_progress->setVisible(
true);
 
 1697    int progressCountdown = reprojectsPerUpdate;
 
 1698    foreach(mosaicSceneItem, *m_mosaicSceneItems) {
 
 1703        QString msg = 
"The file [";
 
 1705        if (mosaicSceneItem->image())
 
 1706          msg += mosaicSceneItem->image()->displayProperties()->displayName();
 
 1708        msg += 
"] is being removed due to not being able to project onto the scene";
 
 1712        mosaicSceneItem->image()->deleteLater();
 
 1715      progressCountdown --;
 
 1716      if (progressCountdown == 0) {
 
 1717        m_progress->setValue(m_progress->value() + 1);
 
 1718        progressCountdown = reprojectsPerUpdate;
 
 1723    m_progress->setValue(m_progress->maximum());
 
 1727    m_progress->setVisible(
false);
 
 
 1731  void MosaicSceneWidget::moveDownOne() {
 
 1735      moveDownOne(cubeToMosaic(props));
 
 1742  double MosaicSceneWidget::moveDownOne(MosaicSceneItem *item) {
 
 1743    MosaicSceneItem *nextDown = 
getNextItem(item, 
false);
 
 1744    double originalZ = item->zValue();
 
 1747      double newZValue = nextDown->zValue() - 1;
 
 1748      moveZ(item, newZValue, 
true);
 
 1757  double MosaicSceneWidget::moveDownOne(Image *image) {
 
 1758    return moveDownOne(cubeToMosaic(image));
 
 1764  QList<double> MosaicSceneWidget::moveDownOne(ImageList *images) {
 
 1765    QList<double> results;
 
 1767    foreach (Image *image, *images) {
 
 1768      results.append(moveDownOne(image));
 
 1775  void MosaicSceneWidget::moveToBottom() {
 
 1776    DisplayProperties *props = qobject_cast<DisplayProperties *>(sender());
 
 1788    double originalZ = item->zValue();
 
 1789    double minZ = minimumZ();
 
 1791    if (originalZ != minZ) {
 
 1793      int newZValue = qRound(minZ - 1);
 
 1794      item->setZValue(newZValue);
 
 1797      m_currentMinimumFootprintZ--;
 
 
 1808  double MosaicSceneWidget::moveToBottom(
Image *image) {
 
 
 1817  QList<double> MosaicSceneWidget::moveToBottom(
ImageList *images) {
 
 1818    QList<double> results;
 
 1820    foreach (
Image *image, *images) {
 
 
 1828  void MosaicSceneWidget::moveUpOne() {
 
 1832      moveUpOne(cubeToMosaic(props));
 
 1839  double MosaicSceneWidget::moveUpOne(MosaicSceneItem *item) {
 
 1840    MosaicSceneItem *nextUp = 
getNextItem(item, 
true);
 
 1841    double originalZ = item->zValue();
 
 1844      double newZValue = nextUp->zValue() + 1;
 
 1845      moveZ(item, newZValue, 
true);
 
 1854  double MosaicSceneWidget::moveUpOne(Image *image) {
 
 1855    return moveUpOne(cubeToMosaic(image));
 
 1861  QList<double> MosaicSceneWidget::moveUpOne(ImageList *images) {
 
 1862    QList<double> results;
 
 1864    foreach (Image *image, *images) {
 
 1865      results.append(moveUpOne(image));
 
 1872  void MosaicSceneWidget::moveToTop() {
 
 1873    DisplayProperties *props = qobject_cast<DisplayProperties *>(sender());
 
 1886    double originalZ = item->zValue();
 
 1887    double maxZ = maximumZ();
 
 1889    if (originalZ != maxZ) {
 
 1891      int newZValue = qRound(maxZ + 1);
 
 1892      item->setZValue(newZValue);
 
 1895      m_currentMaximumFootprintZ++;
 
 
 1916  double MosaicSceneWidget::moveToTop(
Image *image) {
 
 
 1925  QList<double> MosaicSceneWidget::moveToTop(
ImageList *images) {
 
 1926    QList<double> results;
 
 1928    foreach (
Image *image, *images) {
 
 
 1954                                  bool newZValueMightExist) {
 
 1955    double originalZ = sceneItem->zValue();
 
 1957    if (newZValueMightExist) {
 
 1959      m_currentMinimumFootprintZ = 0.0;
 
 1960      m_currentMaximumFootprintZ = 0.0;
 
 1963        double otherItemOrigZ = otherItem->zValue();
 
 1964        double otherItemNewZ = otherItemOrigZ;
 
 1967        if (originalZ > newZ && otherItemOrigZ >= newZ && otherItemOrigZ < originalZ) {
 
 1968          otherItemNewZ = otherItemOrigZ + 1;
 
 1971        else if (originalZ < newZ && otherItemOrigZ <= newZ && otherItemOrigZ > originalZ) {
 
 1972          otherItemNewZ = otherItemOrigZ - 1;
 
 1975        m_currentMinimumFootprintZ = qMin(m_currentMinimumFootprintZ, otherItemNewZ);
 
 1976        m_currentMaximumFootprintZ = qMax(m_currentMaximumFootprintZ, otherItemNewZ);
 
 1977        otherItem->setZValue(otherItemNewZ);
 
 1981    sceneItem->setZValue(newZ);
 
 1983    if (!newZValueMightExist) {
 
 1985      if (originalZ == maximumZ() && newZ < originalZ) {
 
 1986        m_currentMaximumFootprintZ--;
 
 1988      else if (originalZ == minimumZ() && newZ > originalZ) {
 
 1989        m_currentMinimumFootprintZ++;
 
 
 1998                                  bool newZValueMightExist) {
 
 1999    return moveZ(cubeToMosaic(image), newZ, newZValueMightExist);
 
 2003  void MosaicSceneWidget::fitInView() {
 
 2004    if (m_userToolControl) {
 
 2007      DisplayProperties *props = qobject_cast<DisplayProperties *>(sender());
 
 2010        MosaicSceneItem *item = cubeToMosaic(props);
 
 2011        boundingBox = item->boundingRect();
 
 2014        QAction *action = qobject_cast<QAction *>(sender());
 
 2017          ImageList *images = action->data().value<ImageList *>();
 
 2019          foreach (Image *image, *images) {
 
 2020            boundingBox = boundingBox.united(cubeToMosaic(image)->boundingRect());
 
 2025      if (!boundingBox.isNull()) {
 
 2026        double xPadding = boundingBox.width() * 0.10;
 
 2027        double yPadding = boundingBox.height() * 0.10;
 
 2029        boundingBox.setLeft(boundingBox.left() - xPadding);
 
 2030        boundingBox.setRight(boundingBox.right() + xPadding);
 
 2032        boundingBox.setTop(boundingBox.top() - yPadding);
 
 2033        boundingBox.setBottom(boundingBox.bottom() + yPadding);
 
 2035        getView()->fitInView(boundingBox, Qt::KeepAspectRatio);
 
 2036        getView()->centerOn(boundingBox.center());
 
 2042  void MosaicSceneWidget::onSelectionChanged() {
 
 2043    if (!m_blockingSelectionChanged) {
 
 2044      if (!m_queuedSelectionChanged) {
 
 2045        emit queueSelectionChanged();
 
 2046        m_queuedSelectionChanged = 
true;
 
 2049        m_shouldRequeueSelectionChanged = 
true;
 
 2055  void MosaicSceneWidget::onQueuedSelectionChanged() {
 
 2056    m_queuedSelectionChanged = 
false;
 
 2058    if (m_shouldRequeueSelectionChanged) {
 
 2059      m_shouldRequeueSelectionChanged = 
false;
 
 2060      onSelectionChanged();
 
 2063      foreach(MosaicSceneItem *mosaicSceneItem, *m_mosaicSceneItems) {
 
 2064        mosaicSceneItem->updateSelection(
true);
 
 2075    foreach(mosaicSceneItem, *m_mosaicSceneItems) {
 
 2076      if (mosaicSceneItem != item &&
 
 2077          mosaicSceneItem->boundingRect().intersects(item->boundingRect())) {
 
 2079        if ( (up  && mosaicSceneItem->zValue() > item->zValue()) ||
 
 2080            (!up && mosaicSceneItem->zValue() < item->zValue())) {
 
 2083          if (!nextZValueItem) {
 
 2084            nextZValueItem = mosaicSceneItem;
 
 2089            if ((up && mosaicSceneItem->zValue() < nextZValueItem->zValue()) ||
 
 2090                (!up && mosaicSceneItem->zValue() > nextZValueItem->zValue())) {
 
 2091              nextZValueItem = mosaicSceneItem;
 
 2098    return nextZValueItem;
 
 
 2104    return first->zValue() > second->zValue();
 
 2108  MosaicSceneWidget::XmlHandler::XmlHandler(MosaicSceneWidget *scene) {
 
 2110    m_scrollBarXValue = -1;
 
 2111    m_scrollBarYValue = -1;
 
 2112    m_imagesToAdd = NULL;
 
 2114    m_imagesToAdd = 
new ImageList;
 
 2118  MosaicSceneWidget::XmlHandler::~XmlHandler() {
 
 2119    delete m_imagesToAdd;
 
 2120    m_imagesToAdd = NULL;
 
 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);
 
 2128    m_characterData = 
"";
 
 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);
 
 2138          Shape *shape = m_scene->m_directory->project()->shape(
id);
 
 2140            image = 
new Image(shape->cube(), shape->footprint(), 
id);
 
 2144          m_imagesToAdd->append(image);
 
 2145          m_imageZValues.append(zValue);
 
 2149      else if (localName == 
"viewTransform") {
 
 2150        m_scrollBarXValue = atts.value(
"scrollBarXValue").toInt();
 
 2151        m_scrollBarYValue = atts.value(
"scrollBarYValue").toInt();
 
 2159  bool MosaicSceneWidget::XmlHandler::characters(
const QString &ch) {
 
 2160    bool result = XmlStackedHandler::characters(ch);
 
 2163      m_characterData += ch;
 
 2170  bool MosaicSceneWidget::XmlHandler::endElement(
const QString &namespaceURI,
 
 2171      const QString &localName, 
const QString &qName) {
 
 2172    bool result = XmlStackedHandler::endElement(namespaceURI, localName, qName);
 
 2175      if (localName == 
"projection") {
 
 2176        std::stringstream strStream(m_characterData.toStdString());
 
 2177        PvlGroup mappingGroup;
 
 2178        strStream >> mappingGroup;
 
 2179        m_scene->setProjection(mappingGroup);
 
 2181      else if (localName == 
"viewTransform") {
 
 2182        QByteArray hexValues(m_characterData.toLatin1());
 
 2183        QDataStream transformStream(QByteArray::fromHex(hexValues));
 
 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);
 
 2193      else if (localName == 
"toolData") {
 
 2194        PvlObject toolSettings;
 
 2195        std::stringstream strStream(m_characterData.toStdString());
 
 2196        strStream >> toolSettings;
 
 2198        foreach (MosaicTool *tool, *m_scene->m_tools) {
 
 2199          if (tool->projectPvlObjectName() == toolSettings.name()) {
 
 2200            tool->fromPvl(toolSettings);
 
 2204      else if (localName == 
"images" && m_imagesToAdd->count()) {
 
 2205        m_scene->addImages(*m_imagesToAdd);
 
 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,
 
 2211          m_scene->m_currentMaximumFootprintZ = qMax(m_scene->m_currentMaximumFootprintZ,
 
 2217    m_characterData = 
"";
 
QList< QAction * > supportedActions(DataType data)
Returns a list of supported actions for a WorkOrder.
 
Project * project() const
Gets the Project for this directory.
 
@ User
A type of error that could only have occurred due to a mistake on the user's part (e....
 
@ Programmer
This error is for when a programmer made an API call that was illegal.
 
This represents a cube in a project-based GUI interface.
 
Internalizes a list of images and allows for operations on the entire list.
 
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.
 
A graphics scene with improved user-interaction for use with the MosaicSceneWidget.
 
A graphics view that resizes in a more friendly way.
 
A single cube in the mosaic scene.
 
void reproject()
Called anytime the user reprojects the cube.
 
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.
 
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.
 
Contains multiple PvlContainers.
 
A single keyword-value pair.
 
Contains Pvl Groups and Pvl Objects.
 
bool hasObject(const QString &name) const
Returns a boolean value based on whether the object exists in the current PvlObject or not.
 
PvlObjectIterator findObject(const QString &name, PvlObjectIterator beg, PvlObjectIterator end)
Find the index of object with a specified name, between two indexes.
 
@ Traverse
Search child objects.
 
PvlGroupIterator findGroup(const QString &name, PvlGroupIterator beg, PvlGroupIterator end)
Find a group with the specified name, within these indexes.
 
static PvlGroup radiiGroup(QString target)
Creates a Pvl Group with keywords TargetName, EquitorialRadius, and PolarRadius.
 
Provides access to sequential ASCII stream I/O.
 
Manage a stack of content handlers for reading XML files.
 
This is free and unencumbered software released into the public domain.
 
QString toString(bool boolToConvert)
Global function to convert a boolean to a string.
 
int toInt(const QString &string)
Global function to convert from a string to an integer.
 
double toDouble(const QString &string)
Global function to convert from a string to a double.