Unverified Commit c13ad95c authored by kledmundson's avatar kledmundson Committed by GitHub
Browse files

Merge pull request #392 from USGS-Astrogeology/ipce

Merge Ipce into dev. Fixes #5433, #5389, #5049, #5440, #5364, #5416, #5114, #5175, #7414, #4988, #5228, #4981, #5178, #5460, #5436, #5441, #5396.
parents bde69f8b 8999d63e
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -68,6 +68,10 @@ namespace Isis {
   * @param cube The Pvl label from the cube is used to create the Camera object.
   */
  Camera::Camera(Cube &cube) : Sensor(cube) {
    
    m_instrumentId = cube.label()->findGroup("Instrument", 
                        PvlObject::FindOptions::Traverse).findKeyword("InstrumentId")[0];
    
    m_instrumentNameLong = "Unknown";
    m_instrumentNameShort = "Unknown";
    m_spacecraftNameLong = "Unknown";
@@ -2876,6 +2880,16 @@ namespace Isis {
  }
  
  
  /**
   * This method returns the InstrumentId as it appears in the cube.
   *
   * @return QString Returns m_instrumentId
   */
  QString Camera::instrumentId() {
    return m_instrumentId;
  }


  /**
   * This method returns the full instrument name.
   *
+7 −0
Original line number Diff line number Diff line
@@ -241,6 +241,9 @@ namespace Isis {
   *   @history 2017-08-30 Summer Stapleton - Updated documentation. References #4807.
   *   @history 2017-01-11 Christopher Combs - Added bool deleteExisting to SetDistortionMap to 
   *                           prevent a segfault when the distortion map is incomplete. Fixes $5163.
   *   @history 2018-07-12 Summer Stapleton - Added m_instrumentId and instrumentId() in order to 
   *                           collect the InstrumentId from the original cube label for 
   *                           comparisons related to image imports in ipce. References #5460.
   */

  class Camera : public Sensor {
@@ -329,6 +332,8 @@ namespace Isis {
      CameraGroundMap *GroundMap();
      CameraSkyMap *SkyMap();
      
      QString instrumentId();

      QString instrumentNameLong() const;
      QString instrumentNameShort() const;
      QString spacecraftNameLong() const;
@@ -497,6 +502,8 @@ namespace Isis {
      friend class RadarGroundMap;      //!< A friend class to calculate focal length
      friend class RadarSlantRangeMap;  //!< A friend class to calculate focal length
      
      QString m_instrumentId;        //!< The InstrumentId as it appears on the cube.

      QString m_instrumentNameLong;  //!< Full instrument name
      QString m_instrumentNameShort; //!< Shortened instrument name
      QString m_spacecraftNameLong;  //!< Full spacecraft name
+139 −28
Original line number Diff line number Diff line
@@ -23,13 +23,16 @@
#include "IpceMainWindow.h"

#include <QApplication>
#include <QBrush>
#include <QColor>
#include <QDebug>
#include <QDesktopWidget>
#include <QDockWidget>
#include <QMap>
#include <QMapIterator>
#include <QMdiArea>
#include <QObject>
#include <QRect>
#include <QRegExp>
#include <QStringList>
#include <QtWidgets>
@@ -44,6 +47,7 @@


#include "AbstractProjectItemView.h"
#include "ControlHealthMonitorView.h"
#include "Directory.h"
#include "FileName.h"
#include "IException.h"
@@ -80,19 +84,31 @@ namespace Isis {
    m_maxThreadCount = -1;

    QWidget *centralWidget = new QWidget;
    centralWidget->setAutoFillBackground(true);
    QPalette p = centralWidget->palette();
    p.setBrush(QPalette::Window, QBrush(Qt::Dense6Pattern));
    centralWidget->setPalette(p);
    setCentralWidget(centralWidget);
    setTabPosition(Qt::LeftDockWidgetArea, QTabWidget::North);

    setTabPosition(Qt::LeftDockWidgetArea, QTabWidget::South);

    // This was causing some buggy behavior, but this is what we would ultimately like.
    // Allows a user to undock a group of tabs.
    //setDockOptions(GroupedDragging | AllowTabbedDocks);
    //centralWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
    //centralWidget->hide();

    setDockNestingEnabled(true);

    //  Set the splitter frames to a reasonable color/size for resizing the docks.
    setStyleSheet("QMainWindow::separator {background: black; width: 3; height: 3px;}");

    try {
      m_directory = new Directory(this);
      connect(m_directory, SIGNAL( newWidgetAvailable(QWidget *) ),
              this, SLOT( addView(QWidget *) ) );
      connect(m_directory, SIGNAL(viewClosed(QWidget *)),

      connect(m_directory, SIGNAL(closeView(QWidget *)),
              this, SLOT(removeView(QWidget *)));

      connect(m_directory, SIGNAL( directoryCleaned() ),
              this, SLOT( removeAllViews() ) );
      connect(m_directory->project(), SIGNAL(projectLoaded(Project *)),
@@ -117,9 +133,8 @@ namespace Isis {
    projectTreeView->setInternalModel( m_directory->model() );
    projectTreeView->treeView()->expandAll();
    projectTreeView->installEventFilter(this);
    m_projectDock->setWidget(projectTreeView);
    m_projectDock->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);

    m_projectDock->setWidget(projectTreeView);
    addDockWidget(Qt::LeftDockWidgetArea, m_projectDock, Qt::Horizontal);

    m_warningsDock = new QDockWidget("Warnings", this, Qt::SubWindow);
@@ -140,14 +155,11 @@ namespace Isis {
                         QDockWidget::DockWidgetFloatable);
    historyDock->setWhatsThis(tr("This shows all operations performed on the current project."));
    historyDock->setAllowedAreas(Qt::BottomDockWidgetArea);
    addDockWidget(Qt::BottomDockWidgetArea, historyDock);
    m_directory->setHistoryContainer(historyDock);
    tabifyDockWidget(m_warningsDock, historyDock);

    historyDock->raise();

    setTabPosition(Qt::TopDockWidgetArea, QTabWidget::North);

    setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea);
    setCorner(Qt::TopRightCorner, Qt::RightDockWidgetArea);
    setCorner(Qt::BottomLeftCorner, Qt::BottomDockWidgetArea);
@@ -185,26 +197,55 @@ namespace Isis {
   */
  void IpceMainWindow::addView(QWidget *newWidget, Qt::DockWidgetArea area,
                               Qt::Orientation orientation) {

    // JigsawRunWidget is already a QDockWidget, and no modifications need to be made to it
    if (qobject_cast<JigsawRunWidget *>(newWidget)) {
      splitDockWidget(m_projectDock, (QDockWidget*)newWidget, Qt::Vertical);

      // Save view docks for cleanup during a project close
      m_specialDocks.append((QDockWidget *)newWidget);
      return;
    }

    QDockWidget *dock = new QDockWidget(newWidget->windowTitle(), this);
    dock->setWidget(newWidget);
    dock->setObjectName(newWidget->windowTitle());
    dock->setObjectName(newWidget->objectName());
    dock->setAttribute(Qt::WA_DeleteOnClose);
    dock->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetMovable |
                      QDockWidget::DockWidgetFloatable);

    if ( qobject_cast<SensorInfoWidget *>(newWidget) ||
         qobject_cast<TargetInfoWidget *>(newWidget) ||
         qobject_cast<ControlHealthMonitorView *>(newWidget) ||
         qobject_cast<TemplateEditorWidget *>(newWidget)) {
      dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
      splitDockWidget(m_projectDock, dock, Qt::Vertical);

      // Save view docks for cleanup during a project close
      m_specialDocks.append(dock);
    }
    else {
      addDockWidget(area, dock, orientation);
      // Desired behavior of docking views:
      // First regular view (footprint,cubeDisplay) is added to the right of the "special" views
      // (project, sensor, jigsaw, controlHealth).  Adding additional "regular" views are tabbed
      // with the last "regular" view which was added.
      // The following logic not guaranteed to work as intended. If user moves one of the "special"
      // views such as sensor from below the project dock to the right of the project, the following
      // will put the new dock to the right of the moved "special" dock instead of tabbing.  The only
      // way to possibly ensure the intended functionality would be to check for the position of the
      // last added dock and either add or tabify depending on location.  This might also allow the
      // docks to be kept in a single list instead of m_specialDocks & m_viewDocks.
      if (m_viewDocks.count() == 0) {
        addDockWidget(Qt::RightDockWidgetArea, dock, Qt::Horizontal);
      }
      else {
        tabifyDockWidget(m_viewDocks.last(), dock);
        dock->show();
        dock->raise();
      }

      // Save view docks for cleanup during a project close
      m_viewDocks.append(dock);
    }

    // When dock widget is destroyed, make sure the view it holds is also destroyed
@@ -212,28 +253,44 @@ namespace Isis {
    // The list of dock widgets needs cleanup as each view is destroyed
    connect(dock, SIGNAL(destroyed(QObject *)), this, SLOT(cleanupViewDockList(QObject *)));

    // Save view docks for cleanup during a project close
    m_viewDocks.append(dock);
    // Only emit the signal when one view is added just for simplicity; behavior would not change
    // if this was emitted after every addition.
    if (m_viewDocks.size() == 1) {
      emit enableViewActions(true);
    }
  }


  /**
   * Cleans up m_viewDocks when a view is closed (object is destroyed).
   *
   * @param view QObject* The dock widget to remove from the m_viewDocks
   */
  void IpceMainWindow::cleanupViewDockList(QObject *obj) {

    QDockWidget *dock = static_cast<QDockWidget *>(obj);
    if (dock) {
      m_viewDocks.removeAll(dock);
      m_specialDocks.removeAll(dock);
    }

    if (m_viewDocks.size() == 0) {
      emit enableViewActions(false);
    }
  }


  /**
   * This slot is connected from Directory::viewClosed(QWidget *) signal.  It will
   * close the given view and delete the view. This was written to handle
   * This slot is connected from Directory::closeView(QWidget *) signal.  It will close the given
   * view and delete the view.
   *
   * @param view QWidget* The view to close.
   */
  void IpceMainWindow::removeView(QWidget *view) {
    view->close();
    delete view;

    QDockWidget *parentDock = qobject_cast<QDockWidget *>(view->parent());
    removeDockWidget(parentDock);
    delete parentDock;
  }


@@ -245,11 +302,20 @@ namespace Isis {
    foreach (QDockWidget *dock, m_viewDocks) {
      if (dock) {
        removeDockWidget(dock);
        m_viewDocks.removeAll(dock);
        delete dock;
      }
    }

    foreach (QDockWidget *dock, m_specialDocks) {
      if (dock) {
        removeDockWidget(dock);
        m_specialDocks.removeAll(dock);
        delete dock;
      }
    }
    m_viewDocks.clear();
    m_specialDocks.clear();
    emit enableViewActions(false);
}


@@ -358,7 +424,15 @@ namespace Isis {

    QAction *tabViewsAction = new QAction("Tab Views", this);
    connect( tabViewsAction, SIGNAL(triggered()), this, SLOT(tabViews()) );
    connect( this, SIGNAL(enableViewActions(bool)), tabViewsAction, SLOT(setEnabled(bool)) );
    m_viewMenuActions.append(tabViewsAction);
    tabViewsAction->setDisabled(true);  // Disabled on default, until a view is added

    QAction *tileViewsAction = new QAction("Tile Views", this);
    connect( tileViewsAction, SIGNAL(triggered()), this, SLOT(tileViews()) );
    connect( this, SIGNAL(enableViewActions(bool)), tileViewsAction, SLOT(setEnabled(bool)) );
    m_viewMenuActions.append(tileViewsAction);
    tileViewsAction->setDisabled(true); // Disabled on default, until a view is added

    QAction *undoAction = m_directory->undoAction();
    undoAction->setShortcut(Qt::Key_Z | Qt::CTRL);
@@ -497,7 +571,12 @@ namespace Isis {
    QSettings globalSettings(FileName("$HOME/.Isis/" + appName + "/ipce.config").expanded(),
        QSettings::NativeFormat);

    if (project->isTemporaryProject()) {
    // If no config file exists and a user immediately opens a project,
    // the project's geometry will be saved as a default for when ipce is
    // opened again. Previously, the ipce's default size was small,
    // until a user opened ipce (but not a project) and resized to how they
    // wanted it to be sized, then closed ipce.
    if (project->isTemporaryProject() || !globalSettings.contains("geometry")) {
      globalSettings.setValue("geometry", QVariant(geometry()));
    }

@@ -590,6 +669,9 @@ namespace Isis {
   *                           References #4358.
   *   @history 2017-10-17 Tyler Wilson Added a [recent projects] group for the saving and
   *                           restoring of recently opened projects.  References #4492.
   *   @history Kaitlyn Lee 2018-07-09 - Added the value "maximized" in the project settings
   *                           so that a project remembers if it was in fullscreen when saved.
   *                           Fixes #5175.
   */
  void IpceMainWindow::writeSettings(Project *project) {

@@ -603,6 +685,7 @@ namespace Isis {

    projectSettings.setValue("geometry", QVariant(geometry()));
    projectSettings.setValue("windowState", saveState());
    projectSettings.setValue("maximized", isMaximized());
    projectSettings.sync();
  }

@@ -625,6 +708,10 @@ namespace Isis {
   *                Fixes #5075.
   *   @history Makayla Shepherd 2018-06-10 - Settings are read from the project root ipce.config.
   *                If that does not exist then we read from .Isis/ipce/ipce.config.
   *   @history Kaitlyn Lee 2018-07-09 - Added the call showNormal() so when a project is
   *                not saved in fullscreen, the window will resize to the project's
   *                window size. This also fixes the history/warning tabs being misplaced
   *                when opening a project. Fixes #5175.
   */
  void IpceMainWindow::readSettings(Project *project) {
    // Ensure that the Project pointer is not NULL
@@ -658,7 +745,12 @@ namespace Isis {
    QSettings projectSettings(FileName(filePath).expanded(), QSettings::NativeFormat);

    if (!isFullScreen) {
      // If a project was not in fullscreen when saved, restore the project's window size.
      if (!projectSettings.value("maximized").toBool()) {
        showNormal();
      }
      setGeometry(projectSettings.value("geometry").value<QRect>());

      if (!project->isTemporaryProject()) {
        restoreState(projectSettings.value("windowState").toByteArray());
      }
@@ -711,13 +803,7 @@ namespace Isis {
      applyMaxThreadCount();
    }

    // The geom/state isn't enough for main windows to correctly remember
    //   their position and size, so let's restore those on top of
    //   the geom and state.
    if (!projectSettings.value("pos").toPoint().isNull()) {
      move(projectSettings.value("pos").toPoint());
    }
//    m_directory->project()->setClean(true);
    m_directory->project()->setClean(true);
  }


@@ -727,6 +813,9 @@ namespace Isis {
   */
  void IpceMainWindow::closeEvent(QCloseEvent *event) {

    foreach(TemplateEditorWidget *templateEditor, m_directory->templateEditorViews()) {
      templateEditor->saveOption();
    }
    // The active control is checked here for modification because this was the simplest solution
    // vs changing the project clean state every time the control is modified or saved.
    if (!m_directory->project()->isClean() || (m_directory->project()->activeControl() &&
@@ -820,6 +909,28 @@ namespace Isis {
  }


  /**
   * Tile all open attached/detached views
   */
  void IpceMainWindow::tileViews() {
    // splitDockWidget() takes two widgets and tiles them, so an easy way to do
    // this is to grab the first view and tile the rest with the first.
    QDockWidget *firstView = m_viewDocks.first();

    foreach (QDockWidget *currentView, m_viewDocks) {
      // We have to reattach a view before it can be tiled. If it is attached,
      // this will have no affect. We have to call addDockWidget() to untab any views.
      currentView->setFloating(false);
      addDockWidget(Qt::RightDockWidgetArea, currentView, Qt::Horizontal);

      if (currentView == firstView) {
        continue;
      }
      splitDockWidget(firstView, currentView, Qt::Horizontal);
    }
  }


/**
 * Raises the warningWidget to the front of the tabs. Connected to warning signal from directory.
 */
+54 −11
Original line number Diff line number Diff line
@@ -143,8 +143,9 @@ namespace Isis {
   *   @history 2018-06-13 Tracie Sucharski - Fixed cleanup of views and QDockWidgets.
   *   @history 2018-06-13 Kaitlyn Lee - Since views now inherit from QMainWindow, each individual
   *                           view has its own toolbar, so having an active toolbar and tool pad is
   *                           not needed. Removed code adding the save active control net button and
   *                           the toolpad, since control nets can be saved with the project save button.
   *                           not needed. Removed code adding the save active control net button
   *                           and the toolpad, since control nets can be saved with the project
   *                           save button.
   *   @history 2018-06-14 Christopher Combs - Changed addView method to take in JigsawRunWidget as
   *                           a QDockWidget object instead of wrapping it in one.
   *   @history 2018-06-15 Tracie Sucharski - Fixed break to recent projects.  The readSettings
@@ -153,18 +154,57 @@ namespace Isis {
   *   @history 2018-06-18 Makayla Shepherd - Set the QApplication name so that BundleAdjust does
   *                           not output text to the command line for ipce. Fixes #4171.
   *   @history 2018-06-19 Kaitlyn Lee - Added tabViews() and the menu option under the View menu to
   *                           tab the views. Currently, this can tab all attached/detached views. I
   *                           left the line setting dock options to allow grouped dragging, but tabbing
   *                           views does not always work with this enabled. With this option enabled, the
   *                           type of a view will randomly change and setting its type has no effect.
   *                           Use windowType() to get the type. Also added the toolbar title in the
   *                           permanent toolbar constructor.
   *                           tab the views. Currently, this can tab all attached/detached views.
   *                           I left the line setting dock options to allow grouped dragging, but
   *                           tabbing views does not always work with this enabled. With this
   *                           option enabled, the type of a view will randomly change and setting
   *                           its type has no effect. Use windowType() to get the type. Also added
   *                           the toolbar title in the permanent toolbar constructor.
   *   @history 2018-06-22 Tracie Sucharski - Cleanup destruction of dock widgets and the views they
   *                           hold.  Extra destroy slots were causing double deletion of memory.
   *   @history 2018-06-22 Tracie Sucharski - Added a showEvent handler so that the project clean
   *                           state can be reset after the IpceMainWindow::show() causes resize and
   *                           move events which in turn cause the project clean flag to be false
   *                           even though the project has just opened.
   *   @history 2018-07-07 Summer Stapleton - Added check in the closeEvent() for changes to any
   *                           TemplateEditorWidget currently open to create a pop-up warning/
   *                           option to save.
   *   @history 2018-07-09 Kaitlyn Lee - Added tileViews() and the menu option to tile all
   *                           docked/undocked and tabbed/untabbed views. Changed removeView() to
   *                           delete the parent dock widget. If we do not delete the dock widget,
   *                           an empty dock widget will remain where the view used to be.
   *   @history 2018-07-10 Tracie Sucharski - Change initial interface of views to tabbed view.
   *                           Changed the QMainWindow separator to a different color and wider size
   *                           for ease of use.  Create the QMainWindow initial size to prevent the
   *                           Viewports in CubeDnView from being created as a small size.
   *   @history 2018-07-11 Kaitlyn Lee - Added a value in the project settings that stores whether a
   *                           project was in fullscreen or not when saved. If not, we call showNormal()
   *                           to restore the poject's window size. This also fixes the warning/history tabs
   *                           being misplaced when opening a project. Fixes #5175. References #5436.
   *   @history 2018-07-12 Tracie Sucharski - Renamed the signal Directory::viewClosed to
   *                           Directory::closeView since Directory does not close the view but
   *                           indicate that the view needs closing.  This signal is now used by
   *                           more than the cnetEditorView, so updated documentation.  Did a little
   *                           cleanup on the removeView  method by removing some code that
   *                           automatically happens due to connection made on destroyed signal.
   *   @history 2018-07-12 Kaitlyn Lee - Removed code that makes the window fullscreen in memory,
   *                           since this was causing a project's window size to not be restored
   *                           when opening from the command line. Decreased the size and changed
   *                           the color of the splitter. In writeGlobalSettings(), check to see if
   *                           the geometry value does not exist in the config file. This allows the
   *                           geometry to be saved if the config file does not exist and a user
   *                           opens a project. Before, it would not save the geometry because the
   *                           opened project was not temporary. References #5433.
   *   @history 2018-07-17 Kaitlyn Lee - Added signal enableViewActions(bool) to enable/disable
   *                           tab/tile views when views are opened/closed.
   *                           opened project was not temporary. References #5433
   *   @history 2018-07-19 Tracie Sucharski - Keep separate dock lists for the view docks and
   *                           "special" docks such as sensor, target and jigsaw. The
   *                           ControlHealthView is now added under the Project instead of in
   *                           workspace area. Removed unnecessary call to addDock for the History
   *                           widget. It is added with the call to tabifyDockWidget.
   *   @history 2018-07-29 Tracie Sucharski - Set background of centralWidget to a pattern to
   *                           distinguish it from dockable areas.
   */
  class IpceMainWindow : public QMainWindow {
      Q_OBJECT
@@ -172,6 +212,9 @@ namespace Isis {
      explicit IpceMainWindow(QWidget *parent = 0);
      ~IpceMainWindow();

    signals:
      void enableViewActions(bool value);

    public slots:
      void addView(QWidget *newWidget, Qt::DockWidgetArea area = Qt::LeftDockWidgetArea,
                   Qt::Orientation orientation = Qt::Horizontal);
@@ -192,8 +235,10 @@ namespace Isis {
      void enterWhatsThisMode();

      void tabViews();
      void tileViews();

      void raiseWarningTab();

      void cleanupViewDockList(QObject *obj);

    private:
@@ -215,6 +260,7 @@ namespace Isis {
      QDockWidget *m_projectDock;
      QDockWidget *m_warningsDock;

      QList<QDockWidget *> m_specialDocks;  //!< Non-view dock widgets such as jigsawRun
      QList<QDockWidget *> m_viewDocks; //!< QDockWidgets holding the views

      /**
@@ -243,9 +289,6 @@ namespace Isis {
      QList<QAction *> m_helpMenuActions;//!< Internal list of help actions

      QList<QAction *> m_permToolBarActions;//!< Internal list of permanent toolbar actions

      QAction *m_cascadeViewsAction; //!< Action that cascades the mdi area
      QAction *m_tileViewsAction; //!< Action that tiles the mdi area
  };
}

+24 −0
Original line number Diff line number Diff line
@@ -24,11 +24,14 @@

#include <QAction>
#include <QDebug>
#include <QDesktopWidget>
#include <QDragEnterEvent>
#include <QDragMoveEvent>
#include <QDropEvent>
#include <QList>
#include <QMainWindow>
#include <QRect>
#include <QSizePolicy>
#include <QWidget>

#include "ProjectItem.h"
@@ -45,11 +48,32 @@ namespace Isis {
  AbstractProjectItemView::AbstractProjectItemView(QWidget *parent) : QMainWindow(parent) {

    setWindowFlags(Qt::Widget);

    QSizePolicy policy = sizePolicy();
    policy.setHorizontalPolicy(QSizePolicy::Expanding);
    policy.setVerticalPolicy(QSizePolicy::Expanding);
    setSizePolicy(policy);

    m_internalModel = new ProjectItemProxyModel(this);
    setAcceptDrops(true);
  }


  /**
   * Returns the suggested size
   *
   * @return @b QSize The size hint
   */
  QSize AbstractProjectItemView::sizeHint() const {

    //  Size hint is made large as a hack to have the views fill the available dock
    //  space. SizePolicy alone did not work.
    QDesktopWidget deskTop;
    QRect availableSpace = deskTop.availableGeometry(deskTop.primaryScreen());
    return QSize( .89 * availableSpace.width(), .5 * availableSpace.height() );
  }


  /**
   * Sets the model used by the view. If the internal model is a proxy
   * model, it sets the source model.
Loading