diff --git a/kstars/CMakeLists.txt b/kstars/CMakeLists.txt --- a/kstars/CMakeLists.txt +++ b/kstars/CMakeLists.txt @@ -677,6 +677,7 @@ auxiliary/thememanager.cpp auxiliary/schememanager.cpp auxiliary/imageviewer.cpp + auxiliary/xplanetimageviewer.cpp auxiliary/fov.cpp auxiliary/thumbnailpicker.cpp auxiliary/thumbnaileditor.cpp diff --git a/kstars/auxiliary/xplanetimageviewer.h b/kstars/auxiliary/xplanetimageviewer.h new file mode 100644 --- /dev/null +++ b/kstars/auxiliary/xplanetimageviewer.h @@ -0,0 +1,237 @@ + +/*************************************************************************** + XPlanetImageviewer.cpp - Based on: KStars Image Viwer by Thomas Kabelmann + ------------------- + begin : Sun Aug 12, 2018 + copyright : (C) 2018 by Robert Lancaster + email : rlancaste@gmail.com + ***************************************************************************/ +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#pragma once + +#include "auxiliary/filedownloader.h" + +#include +#include +#include +#include "nonlineardoublespinbox.h" +#include +#include +#include +#include +#include +#include +#include "kstarsdata.h" +#include +#include +#include + +class QLabel; +/** + * @class XPlanetImageLabel + * @short XPlanet Image viewer QFrame for the KPlanetImageViewer for KStars + * @author Thomas Kabelmann + * @author Jasem Mutlaq + * @author Robert Lancaster + * @version 1.1 + * + * This image-viewer QFrame automatically resizes the picture. It also receives input from the mouse to + * zoom and pan the XPlanet Image. + */ +class XPlanetImageLabel : public QFrame +{ + Q_OBJECT + public: + explicit XPlanetImageLabel(QWidget *parent); + ~XPlanetImageLabel() override = default; + void setImage(const QImage &img); + void invertPixels(); + void refreshImage(); + + public slots: + void wheelEvent(QWheelEvent *e) override; + void mousePressEvent(QMouseEvent *e) override; + void mouseReleaseEvent(QMouseEvent *e) override; + void mouseMoveEvent(QMouseEvent *e) override; + + signals: + void zoomIn(); + void zoomOut(); + void changePosition(QPoint); + + protected: + void paintEvent(QPaintEvent *e) override; + void resizeEvent(QResizeEvent *) override; + + private: + //Image related + QPixmap pix; + QImage m_Image; + + //Mouse related + bool mouseButtonDown = false; + QPoint lastMousePoint; + bool event(QEvent *event) override; + bool gestureEvent(QGestureEvent *event); + void pinchTriggered(QPinchGesture *gesture); +}; + +/** + * @class XPlanetImageViewer + * @short XPlanet Image viewer window for KStars + * @author Thomas Kabelmann + * @author Jasem Mutlaq + * @author Robert Lancaster + * @version 1.1 + * + * This class is meant to interact with XPlanet and display the results. It has interfaces to control many of the XPlanet Options. + * It can change a number of properties using controls. It works with the XPlanetImageLabel to display the results. It also can work + * with the XPlanetImageLabel to respond to mouse inputs on the ImageLabel and act on them in the Image Viewer. It has a hover mode where + * it hovers over the same planetary body or a remote mode where it views one body from another. It has interfaces for changing the field of + * view, the time, the rotation, and other settings. In hover mode, it can change latitude, longitude, and radius with the mouse inputs. + * It also can animate events so that you can watch xplanet frames like a movie to see solar system events in action. + */ +class XPlanetImageViewer : public QDialog +{ + Q_OBJECT + + public: + /** Create xplanet image viewer from Object */ + explicit XPlanetImageViewer(const QString &obj, QWidget *parent = nullptr); + + /** Destructor. If there is a partially downloaded image file, delete it.*/ + ~XPlanetImageViewer() override; + + /** + * @brief loadImage Load image from local file and display it + * @param filename path to local image + * @return True if opened and displayed, false otherwise + */ + bool loadImage(); + + void startXplanet(); + + private: + /** + * Display the downloaded image. Resize the window to fit the image, If the image is + * larger than the screen, make the image as large as possible while preserving the + * original aspect ratio + */ + bool showImage(); + + /** prepares the output file**/ + bool setupOutputFile(); + + QImage image; + + /** Save the downloaded image to a local file. */ + void saveFile(QUrl &url); + + QFile file; + + QString filename; + + FileDownloader downloadJob; + + XPlanetImageLabel *m_View { nullptr }; + QLabel *m_Caption { nullptr }; + + QUrl lastURL; + + typedef enum { YEARS, MONTHS, DAYS, HOURS, MINS, SECS } timeUnits; + + void setXPlanetDate(KStarsDateTime time); + + //XPlanet strings + QString object; + QString origin; + QString date; + QString dateText; + + //XPlanet numbers + int rotation; + int timeUnit; + int radius; + double FOV; + double lat; + double lon; + + // Time + KStarsDateTime xplanetTime; + bool xplanetRunning = false; + + QComboBox *originSelector {nullptr}; + + // Field of view controls + QPushButton *kstarsFOV {nullptr}; + QPushButton *noFOV {nullptr}; + NonLinearDoubleSpinBox *FOVEdit {nullptr}; + + // Rotation controls + QSpinBox *rotateEdit {nullptr}; + + // Free rotation controls + QLabel *latDisplay {nullptr}; + QLabel *lonDisplay {nullptr}; + QLabel *radDisplay {nullptr}; + QPushButton *freeRotate {nullptr}; + + // Time controls + QLabel *XPlanetTimeDisplay {nullptr}; + QSlider *timeSlider {nullptr}; + QSpinBox *timeEdit {nullptr}; + QComboBox *timeUnitsSelect {nullptr}; + + //Animation controls + QPushButton *runTime {nullptr}; + QTimer *XPlanetTimer {nullptr}; + + + private slots: + + // Saves file to disk. + void saveFileToDisk(); + + // Inverts colors + void invertColors(); + + // Rotation slots + void updateXPlanetRotationEdit(); + void resetXPlanetRotation(); + void invertXPlanetRotation(); + + // Free Rotation slots + void changeXPlanetPosition(QPoint delta); + void slotFreeRotate(); + void updateStates(); + + // Field of View slots + void zoomInXPlanetFOV(); + void zoomOutXPlanetFOV(); + void updateXPlanetFOVEdit(); + void clearXPlanetFOV(); + void setKStarsXPlanetFOV(); + + // Time slots + void updateXPlanetTime(int timeShift); + void updateXPlanetObject(const QString & obj); + void updateXPlanetOrigin(const QString & obj); + void updateXPlanetTimeUnits(int units); + void updateXPlanetTimeEdit(); + void setXPlanetTime(); + void setXPlanetTimetoKStarsTime(); + void resetXPlanetTime(); + + // Animation slots + void incrementXPlanetTime(); + void toggleXPlanetRun(); + +}; diff --git a/kstars/auxiliary/xplanetimageviewer.cpp b/kstars/auxiliary/xplanetimageviewer.cpp new file mode 100644 --- /dev/null +++ b/kstars/auxiliary/xplanetimageviewer.cpp @@ -0,0 +1,1120 @@ + +/*************************************************************************** + XPlanetImageviewer.cpp - Based on: KStars Image Viwer by Thomas Kabelmann + ------------------- + begin : Sun Aug 12, 2018 + copyright : (C) 2018 by Robert Lancaster + email : rlancaste@gmail.com + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "xplanetimageviewer.h" +#include "Options.h" +#include "dialogs/timedialog.h" +#include + +#ifndef KSTARS_LITE +#include "kstars.h" +#endif + +#ifndef KSTARS_LITE +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "skymap.h" +#include "kspaths.h" + +#include +#include + +XPlanetImageLabel::XPlanetImageLabel(QWidget *parent) : QFrame(parent) +{ +#ifndef KSTARS_LITE + grabGesture(Qt::PinchGesture); + setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); + setFrameStyle(QFrame::StyledPanel | QFrame::Plain); + setLineWidth(2); +#endif +} + +void XPlanetImageLabel::setImage(const QImage &img) +{ +#ifndef KSTARS_LITE + m_Image = img; + pix = QPixmap::fromImage(m_Image); +#endif +} + +void XPlanetImageLabel::invertPixels() +{ +#ifndef KSTARS_LITE + m_Image.invertPixels(); + pix = QPixmap::fromImage(m_Image.scaled(width(), height(), Qt::KeepAspectRatio)); +#endif +} + +void XPlanetImageLabel::paintEvent(QPaintEvent *) +{ +#ifndef KSTARS_LITE + QPainter p; + p.begin(this); + int x = 0; + if (pix.width() < width()) + x = (width() - pix.width()) / 2; + p.drawPixmap(x, 0, pix); + p.end(); +#endif +} + +void XPlanetImageLabel::resizeEvent(QResizeEvent *event) +{ + if (event->size() == pix.size()) + return; + + pix = QPixmap::fromImage(m_Image.scaled(event->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation)); +} + +void XPlanetImageLabel::refreshImage() +{ + pix = QPixmap::fromImage(m_Image.scaled(size(), Qt::KeepAspectRatio, Qt::SmoothTransformation)); + update(); +} + +void XPlanetImageLabel::wheelEvent(QWheelEvent *e) +{ + //This attempts to send the wheel event back to the Scroll Area if it was taken from a trackpad + //It should still do the zoom if it is a mouse wheel + if (e->source() == Qt::MouseEventSynthesizedBySystem) + { + QFrame::wheelEvent(e); + } + else + { + if (e->delta() > 0) + emit zoomIn(); + else if (e->delta() < 0) + emit zoomOut(); + e->accept(); + } +} + +bool XPlanetImageLabel::event(QEvent *event) +{ + if (event->type() == QEvent::Gesture) + return gestureEvent(dynamic_cast(event)); + return QFrame::event(event); +} + +bool XPlanetImageLabel::gestureEvent(QGestureEvent *event) +{ + if (QGesture *pinch = event->gesture(Qt::PinchGesture)) + pinchTriggered(dynamic_cast(pinch)); + return true; +} + + +void XPlanetImageLabel::pinchTriggered(QPinchGesture *gesture) +{ + if (gesture->totalScaleFactor() > 1) + emit zoomIn(); + else + emit zoomOut(); +} + + +void XPlanetImageLabel::mousePressEvent(QMouseEvent *e) +{ + mouseButtonDown = true; + lastMousePoint = e->globalPos(); + e->accept(); +} + +void XPlanetImageLabel::mouseReleaseEvent(QMouseEvent *e) +{ + mouseButtonDown = false; + e->accept(); +} + +void XPlanetImageLabel::mouseMoveEvent(QMouseEvent *e) +{ + if(mouseButtonDown) + { + QPoint newPoint = e->globalPos(); + int dx = newPoint.x() - lastMousePoint.x(); + int dy = newPoint.y() - lastMousePoint.y(); + emit changePosition(QPoint(dx, dy)); + lastMousePoint = newPoint; + } + e->accept(); +} + +XPlanetImageViewer::XPlanetImageViewer(const QString &obj, QWidget *parent): QDialog(parent) +{ +#ifndef KSTARS_LITE + lastURL = QUrl::fromLocalFile(QDir::homePath()); + + object=obj; + #ifdef Q_OS_OSX + setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint); + #endif + setAttribute(Qt::WA_DeleteOnClose, true); + setModal(false); + setWindowTitle(i18n("XPlanet Solar System Simulator: %1", object)); + + setXPlanetDate(KStarsData::Instance()->ut()); + if (Options::xplanetFOV()) + FOV = KStars::Instance()->map()->fov(); + else + FOV = 0; + + // Create widget + QFrame *page = new QFrame(this); + + //setMainWidget( page ); + QVBoxLayout *mainLayout = new QVBoxLayout(this); + mainLayout->addWidget(page); + setLayout(mainLayout); + + QWidget *selectorsWidget= new QWidget(this); + QHBoxLayout *selectorsLayout = new QHBoxLayout(selectorsWidget); + selectorsLayout->setMargin(0); + mainLayout->addWidget(selectorsWidget); + + QStringList objects; + objects << i18n("Sun") << i18n("Mercury") << i18n("Venus"); + objects << i18n("Earth") << i18n("Moon"); + objects << i18n("Mars") << i18n("Phobos") << i18n("Deimos"); + objects << i18n("Jupiter") << i18n("Ganymede") << i18n("Io") << i18n("Callisto") << i18n("Europa"); + objects << i18n("Saturn") << i18n("Titan") << i18n("Mimas") << i18n("Enceladus") << i18n("Tethys") << i18n("Dione") << i18n("Rhea") << i18n("Hyperion") << i18n("Iapetus") << i18n("Phoebe"); + objects << i18n("Uranus") << i18n("Umbriel") << i18n("Ariel") << i18n("Miranda") << i18n("Titania") << i18n("Oberon"); + objects << i18n("Neptune") << i18n("Triton"); + + QComboBox *objectSelector = new QComboBox(this); + objectSelector->addItems(objects); + objectSelector->setToolTip(i18n("This allows you to select a new object/target for XPlanet to view")); + selectorsLayout->addWidget(objectSelector); + objectSelector->setCurrentIndex(objectSelector->findText(object)); + connect(objectSelector, SIGNAL(currentTextChanged(QString)), this, SLOT(updateXPlanetObject(QString))); + + origin = i18n("Earth"); + + selectorsLayout->addWidget(new QLabel(i18n("from"),this)); + originSelector = new QComboBox(this); + originSelector->addItems(objects); + originSelector->setToolTip(i18n("This allows you to select a viewing location")); + selectorsLayout->addWidget(originSelector); + originSelector->setCurrentIndex(originSelector->findText(origin)); + connect(originSelector, SIGNAL(currentTextChanged(QString)), this, SLOT(updateXPlanetOrigin(QString))); + + lat = Options::xplanetLatitude().toDouble(); + lon = Options::xplanetLongitude().toDouble(); + radius = 45; + + selectorsLayout->addWidget(new QLabel(i18n("Location:"), this)); + + latDisplay = new QLabel(this); + latDisplay->setToolTip(i18n("XPlanet Latitude, only valid when viewing the object from the same object")); + latDisplay->setText(QString::number(lat)); + latDisplay->setDisabled(true); + selectorsLayout->addWidget(latDisplay); + + selectorsLayout->addWidget(new QLabel(",", this)); + lonDisplay = new QLabel(this); + lonDisplay->setToolTip(i18n("XPlanet Longitude, only valid when viewing the object from the same object")); + lonDisplay->setText(QString::number(lon)); + lonDisplay->setDisabled(true); + selectorsLayout->addWidget(lonDisplay); + + selectorsLayout->addWidget(new QLabel(",", this)); + radDisplay = new QLabel(this); + radDisplay->setToolTip(i18n("XPlanet object radius in %, only valid when viewing the object from the same object")); + radDisplay->setText(QString::number(radius)); + radDisplay->setDisabled(true); + selectorsLayout->addWidget(radDisplay); + + freeRotate = new QPushButton(this); + freeRotate->setIcon(QIcon::fromTheme("object-rotate-left")); + freeRotate->setAttribute(Qt::WA_LayoutUsesWidgetRect); + freeRotate->setMaximumSize(QSize(32,32)); + freeRotate->setMinimumSize(QSize(32,32)); + freeRotate->setCheckable(true); + freeRotate->setToolTip(i18n("Hover over target and freely rotate view with mouse in XPlanet Viewer")); + selectorsLayout->addWidget(freeRotate); + connect(freeRotate, SIGNAL(clicked()), this, SLOT(slotFreeRotate())); + + QPushButton *saveB = new QPushButton(this); + saveB->setIcon(QIcon::fromTheme("document-save")); + saveB->setAttribute(Qt::WA_LayoutUsesWidgetRect); + saveB->setMaximumSize(QSize(32,32)); + saveB->setMinimumSize(QSize(32,32)); + saveB->setToolTip(i18n("Save the image to disk")); + selectorsLayout->addWidget(saveB); + connect(saveB, SIGNAL(clicked()), this, SLOT(saveFileToDisk())); + + QWidget *viewControlsWidget= new QWidget(this); + QHBoxLayout *viewControlsLayout = new QHBoxLayout(viewControlsWidget); + viewControlsLayout->setMargin(0); + mainLayout->addWidget(viewControlsWidget); + + viewControlsLayout->addWidget(new QLabel(i18n("FOV:"), this)); + + FOVEdit = new NonLinearDoubleSpinBox(); + FOVEdit->setDecimals(4); + QList possibleValues; + possibleValues << 0; + for(double i=.001;i<100;i*=1.5) + possibleValues << i; + FOVEdit->setRecommendedValues(possibleValues); + FOVEdit->setValue(0); + FOVEdit->setToolTip(i18n("Sets the FOV to the Specified value. Note: has no effect if hovering over object.")); + viewControlsLayout->addWidget(FOVEdit); + connect(FOVEdit, SIGNAL(valueChanged(double)), this, SLOT(updateXPlanetFOVEdit())); + + kstarsFOV = new QPushButton(this); + kstarsFOV->setIcon(QIcon::fromTheme("zoom-fit-width")); + kstarsFOV->setAttribute(Qt::WA_LayoutUsesWidgetRect); + kstarsFOV->setMaximumSize(QSize(32,32)); + kstarsFOV->setMinimumSize(QSize(32,32)); + kstarsFOV->setToolTip(i18n("Zoom to the current KStars FOV. Note: has no effect if hovering over object.")); + viewControlsLayout->addWidget(kstarsFOV); + connect(kstarsFOV, SIGNAL(clicked()), this, SLOT(setKStarsXPlanetFOV())); + + noFOV = new QPushButton(this); + noFOV->setIcon(QIcon::fromTheme("system-reboot")); + noFOV->setAttribute(Qt::WA_LayoutUsesWidgetRect); + noFOV->setMaximumSize(QSize(32,32)); + noFOV->setMinimumSize(QSize(32,32)); + noFOV->setToolTip(i18n("Optimum FOV for the target, FOV parameter not specified. Note: has no effect if hovering over object.")); + viewControlsLayout->addWidget(noFOV); + connect(noFOV, SIGNAL(clicked()), this, SLOT(clearXPlanetFOV())); + + rotation = 0; + + viewControlsLayout->addWidget(new QLabel(i18n("Rotation:"), this)); + + rotateEdit = new QSpinBox(); + + rotateEdit->setRange(-180, 180); + rotateEdit->setValue(0); + rotateEdit->setSingleStep(10); + rotateEdit->setToolTip(i18n("Set the view rotation to the desired angle")); + viewControlsLayout->addWidget(rotateEdit); + connect(rotateEdit, SIGNAL(valueChanged(int)), this, SLOT(updateXPlanetRotationEdit())); + + QPushButton *invertRotation = new QPushButton(this); + invertRotation->setIcon(QIcon::fromTheme("object-flip-vertical")); + invertRotation->setAttribute(Qt::WA_LayoutUsesWidgetRect); + invertRotation->setMaximumSize(QSize(32,32)); + invertRotation->setMinimumSize(QSize(32,32)); + invertRotation->setToolTip(i18n("Rotate the view 180 degrees")); + viewControlsLayout->addWidget(invertRotation); + connect(invertRotation, SIGNAL(clicked()), this, SLOT(invertXPlanetRotation())); + + QPushButton *resetRotation = new QPushButton(this); + resetRotation->setIcon(QIcon::fromTheme("system-reboot")); + resetRotation->setAttribute(Qt::WA_LayoutUsesWidgetRect); + resetRotation->setMaximumSize(QSize(32,32)); + resetRotation->setMinimumSize(QSize(32,32)); + resetRotation->setToolTip(i18n("Reset view rotation to 0")); + viewControlsLayout->addWidget(resetRotation); + connect(resetRotation, SIGNAL(clicked()), this, SLOT(resetXPlanetRotation())); + + QPushButton *optionsB = new QPushButton(this); + optionsB->setIcon(QIcon::fromTheme("configure")); + optionsB->setAttribute(Qt::WA_LayoutUsesWidgetRect); + optionsB->setMaximumSize(QSize(32,32)); + optionsB->setMinimumSize(QSize(32,32)); + optionsB->setToolTip(i18n("Bring up XPlanet Options")); + viewControlsLayout->addWidget(optionsB); + connect(optionsB, SIGNAL(clicked()), KStars::Instance(), SLOT(slotViewOps())); + + QPushButton *invertB = new QPushButton(this); + invertB->setIcon(QIcon::fromTheme("edit-select-invert")); + invertB->setAttribute(Qt::WA_LayoutUsesWidgetRect); + invertB->setMaximumSize(QSize(32,32)); + invertB->setMinimumSize(QSize(32,32)); + invertB->setToolTip(i18n("Reverse colors of the image. This is useful to enhance contrast at times. This affects " + "only the display and not the saving.")); + viewControlsLayout->addWidget(invertB); + connect(invertB, SIGNAL(clicked()), this, SLOT(invertColors())); + + QWidget *timeWidget= new QWidget(this); + QHBoxLayout *timeLayout = new QHBoxLayout(timeWidget); + mainLayout->addWidget(timeWidget); + timeLayout->setMargin(0); + + xplanetTime = KStarsData::Instance()->lt(); + + QPushButton *setTime = new QPushButton(this); + setTime->setIcon(QIcon::fromTheme("clock")); + setTime->setAttribute(Qt::WA_LayoutUsesWidgetRect); + setTime->setMaximumSize(QSize(32,32)); + setTime->setMinimumSize(QSize(32,32)); + setTime->setToolTip(i18n("Allows you to set the XPlanet time to a different date/time from KStars")); + timeLayout->addWidget(setTime); + connect(setTime, SIGNAL(clicked()), this, SLOT(setXPlanetTime())); + + QPushButton *kstarsTime = new QPushButton(this); + kstarsTime->setIcon(QIcon::fromTheme("system-reboot")); + kstarsTime->setAttribute(Qt::WA_LayoutUsesWidgetRect); + kstarsTime->setMaximumSize(QSize(32,32)); + kstarsTime->setMinimumSize(QSize(32,32)); + kstarsTime->setToolTip(i18n("Sets the XPlanet time to the current KStars time")); + timeLayout->addWidget(kstarsTime); + connect(kstarsTime, SIGNAL(clicked()), this, SLOT(setXPlanetTimetoKStarsTime())); + + XPlanetTimeDisplay = new QLabel(this); + XPlanetTimeDisplay->setToolTip(i18n("Current XPlanet Time")); + timeLayout->addWidget(XPlanetTimeDisplay); + + XPlanetTimeDisplay->setText(xplanetTime.date().toString() + ", " + xplanetTime.time().toString()); + + timeSlider = new QSlider(Qt::Horizontal, this); + timeLayout->addWidget(timeSlider); + timeSlider->setRange(-100, 100); + timeSlider->setToolTip(i18n("This sets the time step from the current XPlanet time, good for viewing events")); + connect(timeSlider, SIGNAL(valueChanged(int)), this, SLOT(updateXPlanetTime(int))); + + timeEdit = new QSpinBox(this); + timeEdit->setRange(-100, 100); + timeEdit->setMaximumWidth(50); + timeEdit->setToolTip(i18n("This sets the time step from the current XPlanet time")); + timeLayout->addWidget(timeEdit); + connect(timeEdit, SIGNAL(valueChanged(int)), this, SLOT(updateXPlanetTimeEdit())); + + timeUnit = MINS; + timeUnitsSelect = new QComboBox(this); + timeLayout->addWidget(timeUnitsSelect); + timeUnitsSelect->addItem(i18n("years")); + timeUnitsSelect->addItem(i18n("months")); + timeUnitsSelect->addItem(i18n("days")); + timeUnitsSelect->addItem(i18n("hours")); + timeUnitsSelect->addItem(i18n("mins")); + timeUnitsSelect->addItem(i18n("secs")); + timeUnitsSelect->setCurrentIndex(MINS); + timeUnitsSelect->setToolTip(i18n("Lets you change the units for the timestep in the animation")); + connect(timeUnitsSelect, SIGNAL(currentIndexChanged(int)), this, SLOT(updateXPlanetTimeUnits(int))); + + XPlanetTimer = new QTimer(this); + XPlanetTimer->setInterval(Options::xplanetAnimationDelay().toInt()); + connect(XPlanetTimer, SIGNAL(timeout()), this, SLOT(incrementXPlanetTime())); + + runTime = new QPushButton(this); + runTime->setIcon(QIcon::fromTheme("media-playback-start")); + runTime->setAttribute(Qt::WA_LayoutUsesWidgetRect); + runTime->setCheckable(true); + runTime->setMaximumSize(QSize(32,32)); + runTime->setMinimumSize(QSize(32,32)); + runTime->setToolTip(i18n("Lets you run the animation")); + timeLayout->addWidget(runTime); + connect(runTime, SIGNAL(clicked()), this, SLOT(toggleXPlanetRun())); + + QPushButton *resetTime = new QPushButton(this); + resetTime->setIcon(QIcon::fromTheme("system-reboot")); + resetTime->setAttribute(Qt::WA_LayoutUsesWidgetRect); + resetTime->setMaximumSize(QSize(32,32)); + resetTime->setMinimumSize(QSize(32,32)); + resetTime->setToolTip(i18n("Resets the animation to 0 timesteps from the current XPlanet Time")); + timeLayout->addWidget(resetTime); + connect(resetTime, SIGNAL(clicked()), this, SLOT(resetXPlanetTime())); + + m_View = new XPlanetImageLabel(page); + m_View->setAutoFillBackground(false); + m_Caption = new QLabel(page); + m_Caption->setAutoFillBackground(true); + m_Caption->setFrameShape(QFrame::StyledPanel); + m_Caption->setText(object); + // Add layout + QVBoxLayout *vlay = new QVBoxLayout(page); + vlay->setSpacing(0); + vlay->setMargin(0); + vlay->addWidget(m_View); + vlay->addWidget(m_Caption); + + + connect(m_View, SIGNAL(zoomIn()), this, SLOT(zoomInXPlanetFOV())); + connect(m_View, SIGNAL(zoomOut()), this, SLOT(zoomOutXPlanetFOV())); + connect(m_View, SIGNAL(changePosition(QPoint)), this, SLOT(changeXPlanetPosition(QPoint))); + + //Reverse colors + QPalette p = palette(); + p.setColor(QPalette::Window, palette().color(QPalette::WindowText)); + p.setColor(QPalette::WindowText, palette().color(QPalette::Window)); + m_Caption->setPalette(p); + m_View->setPalette(p); + +#ifdef Q_OS_OSX + QList qButtons = findChildren(); + for (auto &button : qButtons) + button->setAutoDefault(false); +#endif + updateXPlanetTime(0); + startXplanet(); +#endif +} + +XPlanetImageViewer::~XPlanetImageViewer() +{ + QApplication::restoreOverrideCursor(); +} + +void XPlanetImageViewer::startXplanet() +{ + if(xplanetRunning) + return; + + //This means something failed in the file output + if(!setupOutputFile()) + return; + + QString xPlanetLocation = Options::xplanetPath(); +#ifdef Q_OS_OSX + if (Options::xplanetIsInternal()) + xPlanetLocation = QCoreApplication::applicationDirPath() + "/xplanet/bin/xplanet"; +#endif + + // If Options::xplanetPath() is empty, return + if (xPlanetLocation.isEmpty()) + { + KMessageBox::error(nullptr, i18n("Xplanet binary path is empty in config panel.")); + return; + } + + // If Options::xplanetPath() does not exist, return + const QFileInfo xPlanetLocationInfo(xPlanetLocation); + if (!xPlanetLocationInfo.exists() || !xPlanetLocationInfo.isExecutable()) + { + KMessageBox::error(nullptr, i18n("The configured Xplanet binary does not exist or is not executable.")); + return; + } + + // Create xplanet process + QProcess *xplanetProc = new QProcess(this); + + // Add some options + QStringList args; + + //This specifies the object to be viewed + args << "-body" << object.toLower(); + //This is the date and time requested + args << "-date" << date; + //This is the glare from the sun + args << "-glare" << Options::xplanetGlare(); + args << "-base_magnitude" << Options::xplanetMagnitude(); + //This is the correction for light's travel time. + args << "-light_time"; + + args << "-geometry" << Options::xplanetWidth() + 'x' + Options::xplanetHeight(); + + if(FOV != 0) + args << "-fov" << QString::number(FOV); + //Need to convert to locale for places that don't use decimals?? + //args << "-fov" << fov.setNum(fov());//.replace('.', ','); + + //This rotates the view for different object angles + args << "-rotate" << QString::number(rotation); + + if (Options::xplanetConfigFile()) + args << "-config" << Options::xplanetConfigFilePath(); + if (Options::xplanetStarmap()) + args << "-starmap" << Options::xplanetStarmapPath(); + if (Options::xplanetArcFile()) + args << "-arc_file" << Options::xplanetArcFilePath(); + if (!file.fileName().isEmpty()) + args << "-output" << file.fileName() << "-quality" << Options::xplanetQuality(); + + // Labels + if (Options::xplanetLabel()) + { + args << "-fontsize" << Options::xplanetFontSize() << "-color" + << "0x" + Options::xplanetColor().mid(1) << "-date_format" << Options::xplanetDateFormat(); + + if (Options::xplanetLabelGMT()) + args << "-gmtlabel"; + else + args << "-label"; + if (!Options::xplanetLabelString().isEmpty()) + args << "-label_string" + << "\"" + Options::xplanetLabelString() + "\""; + if (Options::xplanetLabelTL()) + args << "-labelpos" + << "+15+15"; + else if (Options::xplanetLabelTR()) + args << "-labelpos" + << "-15+15"; + else if (Options::xplanetLabelBR()) + args << "-labelpos" + << "-15-15"; + else if (Options::xplanetLabelBL()) + args << "-labelpos" + << "+15-15"; + } + + // Markers + if (Options::xplanetMarkerFile()) + args << "-marker_file" << Options::xplanetMarkerFilePath(); + if (Options::xplanetMarkerBounds()) + args << "-markerbounds" << Options::xplanetMarkerBoundsPath(); + + // Position + // This sets the position from which the planet is viewed. + // Note that setting Latitude and Longitude means that position above the SAME object + + if(object == origin) + { + if (Options::xplanetRandom()) + args << "-random"; + else + args << "-latitude" << QString::number(lat) << "-longitude" << QString::number(lon) << "-radius" << QString::number(radius); + } + else + args << "-origin" << origin; + + // Projection + if (Options::xplanetProjection()) + { + switch (Options::xplanetProjection()) + { + case 1: + args << "-projection" + << "ancient"; + break; + case 2: + args << "-projection" + << "azimuthal"; + break; + case 3: + args << "-projection" + << "bonne"; + break; + case 4: + args << "-projection" + << "gnomonic"; + break; + case 5: + args << "-projection" + << "hemisphere"; + break; + case 6: + args << "-projection" + << "lambert"; + break; + case 7: + args << "-projection" + << "mercator"; + break; + case 8: + args << "-projection" + << "mollweide"; + break; + case 9: + args << "-projection" + << "orthographic"; + break; + case 10: + args << "-projection" + << "peters"; + break; + case 11: + args << "-projection" + << "polyconic"; + break; + case 12: + args << "-projection" + << "rectangular"; + break; + case 13: + args << "-projection" + << "tsc"; + break; + default: + break; + } + if (Options::xplanetBackground()) + { + if (Options::xplanetBackgroundImage()) + args << "-background" << Options::xplanetBackgroundImagePath(); + else + args << "-background" + << "0x" + Options::xplanetBackgroundColorValue().mid(1); + } + } + +#ifdef Q_OS_OSX + if (Options::xplanetIsInternal()) + { + QString searchDir = QCoreApplication::applicationDirPath() + "/xplanet/share/xplanet/"; + args << "-searchdir" << searchDir; + } +#endif + + //This prevents it from running forever. + args << "-num_times" << "1"; + // Run xplanet + + if(Options::xplanetUseFIFO()) + QtConcurrent::run(this, &XPlanetImageViewer::loadImage); + xplanetProc->start(xPlanetLocation, args); + + // qDebug() << "Run:" << xplanetProc->program() << args.join(" "); + xplanetRunning = true; + bool succeeded = xplanetProc->waitForFinished(Options::xplanetTimeout().toInt()); + xplanetRunning = false; + xplanetProc->deleteLater(); + if(succeeded) + { + if(FOV == 0) + m_Caption->setText(i18n("XPlanet View: ") + object + i18n(" from ") + origin + ", " + dateText); + else + m_Caption->setText(i18n("XPlanet View: ") + object + i18n(" from ") + origin + ", " + dateText + i18n(", FOV: ") + QString::number(FOV)); + if(!Options::xplanetUseFIFO()) + loadImage(); + showImage(); + } +} + +bool XPlanetImageViewer::setupOutputFile() +{ + if(Options::xplanetUseFIFO()) + { + if(file.fileName().contains("/tmp/xplanetfifo") && file.exists()) + return true; + file.setFileName(QString("/tmp/xplanetfifo%1.png").arg(QUuid::createUuid().toString().mid(1, 8))); + int fd =0; + if ((fd = mkfifo(file.fileName().toLatin1(), S_IRUSR | S_IWUSR) < 0)) + { + KMessageBox::error(nullptr, i18n("Error making FIFO file %1: %2.", file.fileName(), strerror(errno))); + return false; + } + } + else + { + QDir writableDir; + QString xPlanetDirPath = KSPaths::writableLocation(QStandardPaths::GenericDataLocation) + "xplanet"; + writableDir.mkpath(xPlanetDirPath); + file.setFileName(xPlanetDirPath + QDir::separator() + object + ".png"); + } + + return true; +} + +void XPlanetImageViewer::zoomInXPlanetFOV() +{ + if(origin == object) + { + radius += 5; + radDisplay->setText(QString::number(radius)); + startXplanet(); + } + else + { + FOVEdit->stepDown(); + startXplanet(); + } + +} + +void XPlanetImageViewer::zoomOutXPlanetFOV() +{ + if(origin == object) + { + if(radius > 0) + { + radius -= 5; + radDisplay->setText(QString::number(radius)); + startXplanet(); + } + } + else + { + FOVEdit->stepUp(); + startXplanet(); + } + +} + +void XPlanetImageViewer::updateXPlanetTime(int timeShift){ + + KStarsDateTime shiftedXPlanetTime; + switch(timeUnit) + { + case YEARS: + shiftedXPlanetTime = xplanetTime.addDays(timeShift * 365); + break; + + case MONTHS: + shiftedXPlanetTime = xplanetTime.addDays(timeShift * 30); + break; + + case DAYS: + shiftedXPlanetTime = xplanetTime.addDays(timeShift); + break; + + case HOURS: + shiftedXPlanetTime = xplanetTime.addSecs(timeShift * 3600); + break; + + case MINS: + shiftedXPlanetTime = xplanetTime.addSecs(timeShift * 60); + break; + + case SECS: + shiftedXPlanetTime = xplanetTime.addSecs(timeShift); + break; + } + + setXPlanetDate(shiftedXPlanetTime); + dateText = shiftedXPlanetTime.date().toString() + ", " + shiftedXPlanetTime.time().toString(); + timeEdit->setValue(timeShift); + startXplanet(); +} + +void XPlanetImageViewer::updateXPlanetObject(const QString &obj){ + object = obj; + + setWindowTitle(i18n("XPlanet Solar System Simulator: %1", object)); + if(freeRotate->isChecked()) + originSelector->setCurrentIndex(originSelector->findText(object)); + + startXplanet(); +} + +void XPlanetImageViewer::updateXPlanetOrigin(const QString &obj) +{ + origin = obj; + if(object == origin) + freeRotate->setChecked(true); + else + freeRotate->setChecked(false); + updateStates();//This will update the disabled/enabled states + startXplanet(); +} + +void XPlanetImageViewer::changeXPlanetPosition(QPoint delta) +{ + if(origin == object) + { + double newLon = lon + delta.x(); + double newLat = lat + delta.y(); + + if(newLat > 90) + newLat = 90; + if(newLat < -90) + newLat = -90; + + lon = newLon; + lat = newLat; + + latDisplay->setText(QString::number(lat)); + lonDisplay->setText(QString::number(lon)); + startXplanet(); + } +} + +void XPlanetImageViewer::slotFreeRotate() +{ + if(freeRotate->isChecked()) + originSelector->setCurrentIndex(originSelector->findText(object)); + else + originSelector->setCurrentIndex(originSelector->findText(i18n("Earth"))); +} + +void XPlanetImageViewer::updateStates() +{ + if(freeRotate->isChecked()) + { + FOVEdit->setDisabled(true); + kstarsFOV->setDisabled(true); + noFOV->setDisabled(true); + + latDisplay->setDisabled(false); + lonDisplay->setDisabled(false); + radDisplay->setDisabled(false); + } + else + { + FOVEdit->setDisabled(false); + kstarsFOV->setDisabled(false); + noFOV->setDisabled(false); + + latDisplay->setDisabled(true); + lonDisplay->setDisabled(true); + radDisplay->setDisabled(true); + } +} + +void XPlanetImageViewer::setXPlanetDate(KStarsDateTime time){ + //Note Xplanet uses UT time for everything but we want the labels to all be LT + KStarsDateTime utTime = KStarsData::Instance()->geo()->LTtoUT(time); + QString year, month, day, hour, minute, second; + + if (year.setNum(utTime.date().year()).size() == 1) + year.push_front('0'); + if (month.setNum(utTime.date().month()).size() == 1) + month.push_front('0'); + if (day.setNum(utTime.date().day()).size() == 1) + day.push_front('0'); + if (hour.setNum(utTime.time().hour()).size() == 1) + hour.push_front('0'); + if (minute.setNum(utTime.time().minute()).size() == 1) + minute.push_front('0'); + if (second.setNum(utTime.time().second()).size() == 1) + second.push_front('0'); + + date = year + month + day + '.' + hour + minute + second; + +} + +void XPlanetImageViewer::updateXPlanetTimeUnits(int units) +{ + timeUnit = units; + updateXPlanetTimeEdit(); +} + +void XPlanetImageViewer::updateXPlanetTimeEdit() +{ + int timeShift = timeEdit->text().toInt(); + if(timeSlider->value() != timeShift) + timeSlider->setValue(timeShift); + else + updateXPlanetTime(timeShift); +} + +void XPlanetImageViewer::incrementXPlanetTime() +{ + if(!xplanetRunning) + { + int timeShift = timeEdit->text().toInt(); + if(timeSlider->maximum() == timeShift) + timeSlider->setMaximum(timeSlider->maximum() + 1); + if(timeEdit->maximum() == timeShift) + timeEdit->setMaximum(timeSlider->maximum() + 1); + timeSlider->setValue(timeShift + 1); + } +} + +void XPlanetImageViewer::setXPlanetTime() +{ + QPointer timedialog = new TimeDialog(xplanetTime, KStarsData::Instance()->geo(), this); + if (timedialog->exec() == QDialog::Accepted) + { + xplanetTime = timedialog->selectedDateTime(); + XPlanetTimeDisplay->setText(xplanetTime.date().toString() + ", " + xplanetTime.time().toString()); + int timeShift = 0; + timeSlider->setMaximum(100); + if(timeSlider->value() != timeShift) + timeSlider->setValue(timeShift); + else + updateXPlanetTime(timeShift); + startXplanet(); + } +} + +void XPlanetImageViewer::setXPlanetTimetoKStarsTime() +{ + xplanetTime = KStarsData::Instance()->lt(); + XPlanetTimeDisplay->setText(xplanetTime.date().toString() + ", " + xplanetTime.time().toString()); + int timeShift = 0; + timeSlider->setMaximum(100); + if(timeSlider->value() != timeShift) + timeSlider->setValue(timeShift); + else + updateXPlanetTime(timeShift); + startXplanet(); +} + +void XPlanetImageViewer::resetXPlanetTime() +{ + int timeShift = 0; + timeSlider->setMaximum(100); + timeEdit->setMaximum(100); + if(timeSlider->value() != timeShift) + timeSlider->setValue(timeShift); + else + updateXPlanetTime(timeShift); +} + +void XPlanetImageViewer::toggleXPlanetRun() +{ + if(XPlanetTimer->isActive()) + { + XPlanetTimer->stop(); + } + else + { + XPlanetTimer->setInterval(Options::xplanetAnimationDelay().toInt()); + XPlanetTimer->start(); + } +} + +void XPlanetImageViewer::updateXPlanetFOVEdit() +{ + FOV = FOVEdit->value(); + startXplanet(); +} + +void XPlanetImageViewer::clearXPlanetFOV() +{ + FOV = 0; + FOVEdit->setValue(0); + startXplanet(); +} + +void XPlanetImageViewer::setKStarsXPlanetFOV() +{ + FOV = KStars::Instance()->map()->fov(); + FOVEdit->setValue(FOV); + startXplanet(); +} + +void XPlanetImageViewer::updateXPlanetRotationEdit() +{ + rotation = rotateEdit->value(); + startXplanet(); +} + +void XPlanetImageViewer::resetXPlanetRotation(){ + rotateEdit->setValue(0); +} + +void XPlanetImageViewer::invertXPlanetRotation(){ + rotateEdit->setValue(180); +} + +bool XPlanetImageViewer::loadImage() +{ +#ifndef KSTARS_LITE + if (!image.load(file.fileName())) + { + QString text = i18n("Loading of the image of object %1 failed.", object); + KMessageBox::error(this, text); + return false; + } + return true; +#else + return false; +#endif +} + +bool XPlanetImageViewer::showImage() +{ +#ifndef KSTARS_LITE + + //If the image is larger than screen width and/or screen height, + //shrink it to fit the screen + QRect deskRect = QApplication::desktop()->availableGeometry(); + int w = deskRect.width(); // screen width + int h = deskRect.height(); // screen height + + if (image.width() <= w && image.height() > h) //Window is taller than desktop + image = image.scaled(int(image.width() * h / image.height()), h); + else if (image.height() <= h && image.width() > w) //window is wider than desktop + image = image.scaled(w, int(image.height() * w / image.width())); + else if (image.width() > w && image.height() > h) //window is too tall and too wide + { + //which needs to be shrunk least, width or height? + float fx = float(w) / float(image.width()); + float fy = float(h) / float(image.height()); + if (fx > fy) //width needs to be shrunk less, so shrink to fit in height + image = image.scaled(int(image.width() * fy), h); + else //vice versa + image = image.scaled(w, int(image.height() * fx)); + } + const bool initialLoad = !isVisible(); + + show(); // hide is default + + m_View->setImage(image); + w = image.width(); + + //If the caption is wider than the image, set the window size + //to fit the caption + if (m_Caption->width() > w) + w = m_Caption->width(); + if(initialLoad) + resize(w, image.height()); + else + { + m_View->refreshImage(); + } + + update(); + show(); + + return true; +#else + return false; +#endif +} + +void XPlanetImageViewer::saveFileToDisk() +{ +#ifndef KSTARS_LITE + + QUrl newURL = QFileDialog::getSaveFileUrl(KStars::Instance(), i18n("Save Image"), lastURL); // save-dialog with default filename + if (!newURL.isEmpty()) + { + if (newURL.toLocalFile().endsWith(QLatin1String(".png")) == false) + newURL.setPath(newURL.toLocalFile() + ".png"); + + QFile f(newURL.toLocalFile()); + if (f.exists()) + { + int r = KMessageBox::warningContinueCancel(parentWidget(), + i18n("A file named \"%1\" already exists. " + "Overwrite it?", + newURL.fileName()), + i18n("Overwrite File?"), KStandardGuiItem::overwrite()); + if (r == KMessageBox::Cancel) + return; + + f.remove(); + } + + lastURL = QUrl(newURL.toString(QUrl::RemoveFilename)); + + saveFile(newURL); + } +#endif +} + +void XPlanetImageViewer::saveFile(QUrl &url) +{ +#ifndef KSTARS_LITE + if (file.copy(url.toLocalFile()) == false) + { + QString text = i18n("Saving of the image %1 failed.", url.toString()); + KMessageBox::error(this, text); + } + else + KStars::Instance()->statusBar()->showMessage(i18n("Saved image to %1", url.toString())); +#endif +} + +void XPlanetImageViewer::invertColors() +{ +#ifndef KSTARS_LITE + // Invert colors + m_View->invertPixels(); + m_View->update(); +#endif +} + diff --git a/kstars/data/kstarsui.rc b/kstars/data/kstarsui.rc --- a/kstars/data/kstarsui.rc +++ b/kstars/data/kstarsui.rc @@ -1,6 +1,6 @@ - + &File @@ -73,6 +73,7 @@ + diff --git a/kstars/kspopupmenu.cpp b/kstars/kspopupmenu.cpp --- a/kstars/kspopupmenu.cpp +++ b/kstars/kspopupmenu.cpp @@ -398,11 +398,7 @@ obj->type() != SkyObject::COMET) // FIXME: We now have asteroids -- so should this not be isMajorPlanet() || Pluto? { - //QMenu *xplanetSubmenu = new QMenu(); - //xplanetSubmenu->setTitle( i18n( "Print Xplanet view" ) ); - addAction(i18n("View in XPlanet"), map, SLOT(slotXplanetToWindow())); - //xplanetSubmenu->addAction( i18n( "To file..." ), map, SLOT( slotXplanetToFile() ) ); - //addMenu( xplanetSubmenu ); + addAction(i18n("View in XPlanet"), map, SLOT(slotStartXplanetViewer())); } addSeparator(); addINDI(); diff --git a/kstars/kstars.kcfg b/kstars/kstars.kcfg --- a/kstars/kstars.kcfg +++ b/kstars/kstars.kcfg @@ -1073,10 +1073,20 @@ Xplanet binary path KSUtils::getDefaultPath("XplanetPath") - - - Set the window’s title. - + + + Option to use a FIFO file instead of saving to the hard disk + true + + + + How long to wait for XPlanet before giving up in milliseconds + 1000 + + + + How long to pause between frames in the XPlanet Animation + 100 @@ -1169,16 +1179,6 @@ The default is no projection. Multiple bodies will not be shown if this option is specified, although shadows will still be drawn. 0 - - - If true, update view. - false - - - - Number of seconds to wait before updating - 60 - Use a file as the background image, with the planet to be superimposed upon it. This option is only meaningful with the -projection option. A color may also be supplied. diff --git a/kstars/kstarsinit.cpp b/kstars/kstarsinit.cpp --- a/kstars/kstarsinit.cpp +++ b/kstars/kstarsinit.cpp @@ -414,6 +414,9 @@ << i18n("What's Interesting...") << QKeySequence(Qt::CTRL + Qt::Key_W); //#endif + actionCollection()->addAction("XPlanet", map(), SLOT(slotStartXplanetViewer())) + << i18n("XPlanet Solar System Simulator") << QKeySequence(Qt::CTRL + Qt::Key_X); + actionCollection()->addAction("skycalendar", this, SLOT(slotCalendar())) << i18n("Sky Calendar"); #ifdef HAVE_INDI diff --git a/kstars/skymap.h b/kstars/skymap.h --- a/kstars/skymap.h +++ b/kstars/skymap.h @@ -457,11 +457,8 @@ void slotToggleGL(); #endif - /** Run Xplanet to print a view in a Window*/ - void slotXplanetToWindow(); - - /** Run Xplanet to print a view in a file */ - void slotXplanetToFile(); + /** Run Xplanet Viewer to display images of the planets*/ + void slotStartXplanetViewer(); /** Render eyepiece view */ void slotEyepieceView(); diff --git a/kstars/skymap.cpp b/kstars/skymap.cpp --- a/kstars/skymap.cpp +++ b/kstars/skymap.cpp @@ -25,6 +25,7 @@ #include "kstars_debug.h" #include "fov.h" #include "imageviewer.h" +#include "xplanetimageviewer.h" #include "ksdssdownloader.h" #include "kspaths.h" #include "kspopupmenu.h" @@ -1268,226 +1269,12 @@ return (slewing || (clockSlewing && data->clock()->isActive())); } -void SkyMap::startXplanet(const QString &outputFile) +void SkyMap::slotStartXplanetViewer() { - QString year, month, day, hour, minute, seconde, fov; - - QString xPlanetLocation = Options::xplanetPath(); -#ifdef Q_OS_OSX - if (Options::xplanetIsInternal()) - xPlanetLocation = QCoreApplication::applicationDirPath() + "/xplanet/bin/xplanet"; -#endif - - // If Options::xplanetPath() is empty, return - if (xPlanetLocation.isEmpty()) - { - KMessageBox::error(nullptr, i18n("Xplanet binary path is empty in config panel.")); - return; - } - - // If Options::xplanetPath() does not exist, return - const QFileInfo xPlanetLocationInfo(xPlanetLocation); - if (!xPlanetLocationInfo.exists() || !xPlanetLocationInfo.isExecutable()) - { - KMessageBox::error(nullptr, i18n("The configured Xplanet binary does not exist or is not executable.")); - return; - } - - // Format date - if (year.setNum(data->ut().date().year()).size() == 1) - year.push_front('0'); - if (month.setNum(data->ut().date().month()).size() == 1) - month.push_front('0'); - if (day.setNum(data->ut().date().day()).size() == 1) - day.push_front('0'); - if (hour.setNum(data->ut().time().hour()).size() == 1) - hour.push_front('0'); - if (minute.setNum(data->ut().time().minute()).size() == 1) - minute.push_front('0'); - if (seconde.setNum(data->ut().time().second()).size() == 1) - seconde.push_front('0'); - - // Create xplanet process - QProcess *xplanetProc = new QProcess; - - // Add some options - QStringList args; - args << "-body" << clickedObject()->name().toLower() << "-geometry" - << Options::xplanetWidth() + 'x' + Options::xplanetHeight() << "-date" - << year + month + day + '.' + hour + minute + seconde << "-glare" << Options::xplanetGlare() - << "-base_magnitude" << Options::xplanetMagnitude() << "-light_time" - << "-window"; - - // General options - if (!Options::xplanetTitle().isEmpty()) - args << "-window_title" - << "\"" + Options::xplanetTitle() + "\""; - if (Options::xplanetFOV()) - args << "-fov" << fov.setNum(this->fov()).replace('.', ','); - if (Options::xplanetConfigFile()) - args << "-config" << Options::xplanetConfigFilePath(); - if (Options::xplanetStarmap()) - args << "-starmap" << Options::xplanetStarmapPath(); - if (Options::xplanetArcFile()) - args << "-arc_file" << Options::xplanetArcFilePath(); - if (Options::xplanetWait()) - args << "-wait" << Options::xplanetWaitValue(); - if (!outputFile.isEmpty()) - args << "-output" << outputFile << "-quality" << Options::xplanetQuality(); - - // Labels - if (Options::xplanetLabel()) - { - args << "-fontsize" << Options::xplanetFontSize() << "-color" - << "0x" + Options::xplanetColor().mid(1) << "-date_format" << Options::xplanetDateFormat(); - - if (Options::xplanetLabelGMT()) - args << "-gmtlabel"; - else - args << "-label"; - if (!Options::xplanetLabelString().isEmpty()) - args << "-label_string" - << "\"" + Options::xplanetLabelString() + "\""; - if (Options::xplanetLabelTL()) - args << "-labelpos" - << "+15+15"; - else if (Options::xplanetLabelTR()) - args << "-labelpos" - << "-15+15"; - else if (Options::xplanetLabelBR()) - args << "-labelpos" - << "-15-15"; - else if (Options::xplanetLabelBL()) - args << "-labelpos" - << "+15-15"; - } - - // Markers - if (Options::xplanetMarkerFile()) - args << "-marker_file" << Options::xplanetMarkerFilePath(); - if (Options::xplanetMarkerBounds()) - args << "-markerbounds" << Options::xplanetMarkerBoundsPath(); - - // Position - if (Options::xplanetRandom()) - args << "-random"; + if(clickedObject()) + new XPlanetImageViewer(clickedObject()->name(), this); else - args << "-latitude" << Options::xplanetLatitude() << "-longitude" << Options::xplanetLongitude(); - - // Projection - if (Options::xplanetProjection()) - { - switch (Options::xplanetProjection()) - { - case 1: - args << "-projection" - << "ancient"; - break; - case 2: - args << "-projection" - << "azimuthal"; - break; - case 3: - args << "-projection" - << "bonne"; - break; - case 4: - args << "-projection" - << "gnomonic"; - break; - case 5: - args << "-projection" - << "hemisphere"; - break; - case 6: - args << "-projection" - << "lambert"; - break; - case 7: - args << "-projection" - << "mercator"; - break; - case 8: - args << "-projection" - << "mollweide"; - break; - case 9: - args << "-projection" - << "orthographic"; - break; - case 10: - args << "-projection" - << "peters"; - break; - case 11: - args << "-projection" - << "polyconic"; - break; - case 12: - args << "-projection" - << "rectangular"; - break; - case 13: - args << "-projection" - << "tsc"; - break; - default: - break; - } - if (Options::xplanetBackground()) - { - if (Options::xplanetBackgroundImage()) - args << "-background" << Options::xplanetBackgroundImagePath(); - else - args << "-background" - << "0x" + Options::xplanetBackgroundColorValue().mid(1); - } - } - - // We add this option at the end otherwise it does not work (???) - args << "-origin" - << "earth"; - - // Run xplanet - //qDebug() << "Run:" << xplanetProc->program().join(" "); - -#ifdef Q_OS_OSX - if (Options::xplanetIsInternal()) - { - QString searchDir = QCoreApplication::applicationDirPath() + "/xplanet/share/xplanet/"; - args << "-searchdir" << searchDir; - } -#endif - xplanetProc->start(xPlanetLocation, args); - if (xplanetProc) - { - xplanetProc->waitForFinished(1000); - new ImageViewer(QUrl::fromLocalFile(outputFile), - "XPlanet View: " + clickedObject()->name() + ", " + data->lt().date().toString() + ", " + - data->lt().time().toString(), - this); - //iv->show(); - } - else - { - KMessageBox::sorry(this, i18n("XPlanet Program Error")); - } + new XPlanetImageViewer(i18n("Saturn"), this); } -void SkyMap::slotXplanetToWindow() -{ - QDir writableDir; - QString xPlanetDirPath = KSPaths::writableLocation(QStandardPaths::GenericDataLocation) + "xplanet"; - writableDir.mkpath(xPlanetDirPath); - QString xPlanetPath = xPlanetDirPath + QDir::separator() + clickedObject()->name() + ".png"; - startXplanet(xPlanetPath); -} -void SkyMap::slotXplanetToFile() -{ - QString filename = QFileDialog::getSaveFileName(); - if (!filename.isEmpty()) - { - startXplanet(filename); - } -} diff --git a/kstars/xplanet/opsxplanet.h b/kstars/xplanet/opsxplanet.h --- a/kstars/xplanet/opsxplanet.h +++ b/kstars/xplanet/opsxplanet.h @@ -32,7 +32,7 @@ KStars *ksw { nullptr }; private slots: - void slotUpdateWidgets(bool on); + void showXPlanetMapsDirectory(); void slotConfigFileWidgets(bool on); void slotStarmapFileWidgets(bool on); void slotArcFileWidgets(bool on); diff --git a/kstars/xplanet/opsxplanet.cpp b/kstars/xplanet/opsxplanet.cpp --- a/kstars/xplanet/opsxplanet.cpp +++ b/kstars/xplanet/opsxplanet.cpp @@ -19,6 +19,7 @@ #include "kstars.h" #include "kstarsdata.h" #include "Options.h" +#include OpsXplanet::OpsXplanet(KStars *_ks) : QFrame(_ks), ksw(_ks) { @@ -52,7 +53,6 @@ kcfg_XplanetProjection->addItem(i18nc("Map projection method", "TSC"), "tsc"); // Enable/Disable somme widgets - connect(kcfg_XplanetWait, SIGNAL(toggled(bool)), SLOT(slotUpdateWidgets(bool))); connect(kcfg_XplanetConfigFile, SIGNAL(toggled(bool)), SLOT(slotConfigFileWidgets(bool))); connect(kcfg_XplanetStarmap, SIGNAL(toggled(bool)), SLOT(slotStarmapFileWidgets(bool))); connect(kcfg_XplanetArcFile, SIGNAL(toggled(bool)), SLOT(slotArcFileWidgets(bool))); @@ -62,8 +62,6 @@ connect(kcfg_XplanetProjection, SIGNAL(currentIndexChanged(int)), SLOT(slotProjectionWidgets(int))); connect(kcfg_XplanetBackground, SIGNAL(toggled(bool)), SLOT(slotBackgroundWidgets(bool))); - kcfg_XplanetWaitValue->setEnabled(Options::xplanetWait()); - textLabelXplanetSecondes->setEnabled(Options::xplanetWait()); kcfg_XplanetConfigFilePath->setEnabled(Options::xplanetConfigFile()); kcfg_XplanetStarmapPath->setEnabled(Options::xplanetStarmap()); kcfg_XplanetArcFilePath->setEnabled(Options::xplanetArcFile()); @@ -96,6 +94,20 @@ kcfg_XplanetBackgroundColorValue->setEnabled(Options::xplanetBackgroundImage()); if (Options::xplanetProjection() == 0) groupBoxBackground->setEnabled(false); + + connect(openXPlanetMaps, SIGNAL(clicked()),this,SLOT(showXPlanetMapsDirectory())); +} + +void OpsXplanet::showXPlanetMapsDirectory() +{ + + QString xplanetMapsDir; + if (Options::xplanetIsInternal()) + xplanetMapsDir = QCoreApplication::applicationDirPath() + "/xplanet/share/xplanet/images"; + else + xplanetMapsDir = Options::xplanetPath() + "../share/xplanet/images"; + QUrl path = QUrl::fromLocalFile(xplanetMapsDir); + QDesktopServices::openUrl(path); } void OpsXplanet::toggleXPlanetInternal() @@ -107,12 +119,6 @@ kcfg_XplanetPath->setText(KSUtils::getDefaultPath("XplanetPath")); } -void OpsXplanet::slotUpdateWidgets(bool on) -{ - kcfg_XplanetWaitValue->setEnabled(on); - textLabelXplanetSecondes->setEnabled(on); -} - void OpsXplanet::slotConfigFileWidgets(bool on) { kcfg_XplanetConfigFilePath->setEnabled(on); diff --git a/kstars/xplanet/opsxplanet.ui b/kstars/xplanet/opsxplanet.ui --- a/kstars/xplanet/opsxplanet.ui +++ b/kstars/xplanet/opsxplanet.ui @@ -6,7 +6,7 @@ 0 0 - 621 + 622 647 @@ -31,26 +31,43 @@ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - Window title: + + + + 0 - + + 0 + + + + + + + + + + + + Xplanet path: + + + + - - + + 0 0 - Title of xplanet window + Xplanet binary path - Set the window’s title. + Enter here the path of xplanet binary. @@ -84,7 +101,7 @@ Set the width of window - Set the width of window + Set the width of the xplanet image @@ -110,7 +127,7 @@ Set the height of window - Set the height of window + Set the height of the xplanet image @@ -136,45 +153,33 @@ - - - - - 0 - 0 - - + + - Xplanet binary path + The time KStars will wait for XPlanet to complete before giving up. - - Enter here the path of xplanet binary. + + + + + + XPlanet Timeout - - - - 0 + + + + Animation Delay - - 0 + + + + + + The delay between frames for the animation - - - - - - - - - - - Xplanet path: - - - - + @@ -202,7 +207,7 @@ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - + Use kstars's FOV? @@ -215,51 +220,17 @@ - - - - Update? - - - If checked, update view. - - - Update every - - - - - - - - - Number of seconds to wait before updating - - - Number of seconds to wait before updating - - - 99999 - - - - - - - seconds - - - - + + - + Glare of Sun: - + @@ -275,14 +246,14 @@ - + Base magnitude: - + @@ -298,7 +269,7 @@ - + Use custom star map? @@ -311,7 +282,7 @@ - + @@ -327,7 +298,7 @@ - + @@ -343,7 +314,7 @@ - + @@ -359,20 +330,40 @@ - + Config file: - + Arc file: + + + + Use kstars's FOV? + + + <html><head/><body><p>If checked, XPlanet will use a FIFO file in the /tmp directory to temporarily save the XPlanet image for KStars to load them and update the view. If not checked, XPlanet will actually save the files to the XPlanet folder in the KStars data directory. Using a FIFO file should save the hard disk from excessive reads/writes and may offer a performance enhancement.</p></body></html> + + + Use FIFO File + + + + + + + (saves to memory instead of a hard disk) + + + @@ -434,6 +425,26 @@ + + + + XPlanet Requires Maps in order to function properly. It does not ship with a lot of planetary maps. You need to download some in order to get the full benefits of XPlanet. This is a good place to start: <a href =http://xplanet.sourceforge.net/maps.php>http://xplanet.sourceforge.net/maps.php</a> + + + true + + + true + + + + + + + XPlanet Planet Maps + + + @@ -1012,12 +1023,9 @@ tab kcfg_XplanetPath - kcfg_XplanetTitle kcfg_XplanetWidth kcfg_XplanetHeight kcfg_XplanetFOV - kcfg_XplanetWait - kcfg_XplanetWaitValue kcfg_XplanetGlare kcfg_XplanetMagnitude kcfg_XplanetConfigFile