File indexing completed on 2024-03-24 15:15:24
0001 /* 0002 SPDX-FileCopyrightText: Thomas Kabelmann 0003 SPDX-FileCopyrightText: 2018 Robert Lancaster <rlancaste@gmail.com> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include "xplanetimageviewer.h" 0009 #include "Options.h" 0010 #include "dialogs/timedialog.h" 0011 #include "ksnotification.h" 0012 0013 #include <QtConcurrent> 0014 0015 #ifndef KSTARS_LITE 0016 #include "kstars.h" 0017 #endif 0018 0019 #ifndef KSTARS_LITE 0020 #include <KMessageBox> 0021 #endif 0022 0023 #include <QFileDialog> 0024 #include <QPainter> 0025 #include <QResizeEvent> 0026 #include <QStatusBar> 0027 #include <QTemporaryFile> 0028 #include <QVBoxLayout> 0029 #include <QPushButton> 0030 #include <QApplication> 0031 #include <QScreen> 0032 #include <QSlider> 0033 #include "skymap.h" 0034 #include "kspaths.h" 0035 #include "fov.h" 0036 0037 #include <QUuid> 0038 #include <sys/stat.h> 0039 #include <QInputDialog> 0040 0041 typedef enum 0042 { 0043 SUN, MERCURY, VENUS, 0044 EARTH, MOON, 0045 MARS, PHOBOS, DEIMOS, 0046 JUPITER, GANYMEDE, IO, CALLISTO, EUROPA, 0047 SATURN, TITAN, MIMAS, ENCELADUS, TETHYS, DIONE, RHEA, HYPERION, IAPETUS, PHOEBE, 0048 URANUS, UMBRIEL, ARIEL, MIRANDA, TITANIA, OBERON, 0049 NEPTUNE, TRITON 0050 } objects; 0051 0052 XPlanetImageLabel::XPlanetImageLabel(QWidget *parent) : QFrame(parent) 0053 { 0054 #ifndef KSTARS_LITE 0055 grabGesture(Qt::PinchGesture); 0056 setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); 0057 setFrameStyle(QFrame::StyledPanel | QFrame::Plain); 0058 setLineWidth(2); 0059 #endif 0060 } 0061 0062 void XPlanetImageLabel::setImage(const QImage &img) 0063 { 0064 #ifndef KSTARS_LITE 0065 m_Image = img; 0066 m_Pix = QPixmap::fromImage(m_Image); 0067 #endif 0068 } 0069 0070 void XPlanetImageLabel::invertPixels() 0071 { 0072 #ifndef KSTARS_LITE 0073 m_Image.invertPixels(); 0074 m_Pix = QPixmap::fromImage(m_Image.scaled(width(), height(), Qt::KeepAspectRatio)); 0075 #endif 0076 } 0077 0078 void XPlanetImageLabel::paintEvent(QPaintEvent *) 0079 { 0080 #ifndef KSTARS_LITE 0081 QPainter p; 0082 p.begin(this); 0083 int x = 0; 0084 if (m_Pix.width() < width()) 0085 x = (width() - m_Pix.width()) / 2; 0086 p.drawPixmap(x, 0, m_Pix); 0087 p.end(); 0088 #endif 0089 } 0090 0091 void XPlanetImageLabel::resizeEvent(QResizeEvent *event) 0092 { 0093 if (event->size() == m_Pix.size()) 0094 return; 0095 0096 m_Pix = QPixmap::fromImage(m_Image.scaled(event->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation)); 0097 } 0098 0099 void XPlanetImageLabel::refreshImage() 0100 { 0101 m_Pix = QPixmap::fromImage(m_Image.scaled(size(), Qt::KeepAspectRatio, Qt::SmoothTransformation)); 0102 update(); 0103 } 0104 0105 void XPlanetImageLabel::wheelEvent(QWheelEvent *e) 0106 { 0107 //This attempts to send the wheel event back to the Scroll Area if it was taken from a trackpad 0108 //It should still do the zoom if it is a mouse wheel 0109 if (e->source() == Qt::MouseEventSynthesizedBySystem) 0110 { 0111 QFrame::wheelEvent(e); 0112 } 0113 else 0114 { 0115 if (e->angleDelta().y() > 0) 0116 emit zoomIn(); 0117 else if (e->angleDelta().y() < 0) 0118 emit zoomOut(); 0119 e->accept(); 0120 } 0121 } 0122 0123 bool XPlanetImageLabel::event(QEvent *event) 0124 { 0125 if (event->type() == QEvent::Gesture) 0126 return gestureEvent(dynamic_cast<QGestureEvent *>(event)); 0127 return QFrame::event(event); 0128 } 0129 0130 bool XPlanetImageLabel::gestureEvent(QGestureEvent *event) 0131 { 0132 if (QGesture *pinch = event->gesture(Qt::PinchGesture)) 0133 pinchTriggered(dynamic_cast<QPinchGesture *>(pinch)); 0134 return true; 0135 } 0136 0137 0138 void XPlanetImageLabel::pinchTriggered(QPinchGesture *gesture) 0139 { 0140 if (gesture->totalScaleFactor() > 1) 0141 emit zoomIn(); 0142 else 0143 emit zoomOut(); 0144 } 0145 0146 0147 void XPlanetImageLabel::mousePressEvent(QMouseEvent *e) 0148 { 0149 m_MouseButtonDown = true; 0150 m_LastMousePoint = e->globalPos(); 0151 e->accept(); 0152 } 0153 0154 void XPlanetImageLabel::mouseReleaseEvent(QMouseEvent *e) 0155 { 0156 m_MouseButtonDown = false; 0157 e->accept(); 0158 } 0159 0160 void XPlanetImageLabel::mouseMoveEvent(QMouseEvent *e) 0161 { 0162 if(m_MouseButtonDown) 0163 { 0164 QPoint newPoint = e->globalPos(); 0165 int dx = newPoint.x() - m_LastMousePoint.x(); 0166 int dy = newPoint.y() - m_LastMousePoint.y(); 0167 if(e->buttons() & Qt::RightButton) 0168 emit changeLocation(QPoint(dx, dy)); 0169 if(e->buttons() & Qt::LeftButton) 0170 emit changePosition(QPoint(dx, dy)); 0171 m_LastMousePoint = newPoint; 0172 } 0173 e->accept(); 0174 } 0175 0176 XPlanetImageViewer::XPlanetImageViewer(const QString &obj, QWidget *parent): QDialog(parent) 0177 { 0178 #ifndef KSTARS_LITE 0179 m_LastFile = QDir::homePath(); 0180 0181 #ifdef Q_OS_OSX 0182 setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint); 0183 #endif 0184 setAttribute(Qt::WA_DeleteOnClose, true); 0185 setModal(false); 0186 setWindowTitle(i18nc("@title:window", "XPlanet Solar System Simulator: %1", obj)); 0187 0188 setXPlanetDate(KStarsData::Instance()->ut()); 0189 0190 // Create widget 0191 QFrame *page = new QFrame(this); 0192 0193 //setMainWidget( page ); 0194 QVBoxLayout *mainLayout = new QVBoxLayout(this); 0195 mainLayout->addWidget(page); 0196 setLayout(mainLayout); 0197 0198 QWidget *selectorsWidget = new QWidget(this); 0199 QHBoxLayout *selectorsLayout = new QHBoxLayout(selectorsWidget); 0200 selectorsLayout->setContentsMargins(0, 0, 0, 0); 0201 mainLayout->addWidget(selectorsWidget); 0202 0203 m_ObjectNames << i18n("Sun") << i18n("Mercury") << i18n("Venus"); 0204 m_objectDefaultFOVs << 0.74818 << 0.004 << 0.02; 0205 m_ObjectNames << i18n("Earth") << i18n("Moon"); 0206 m_objectDefaultFOVs << 1.0 << 0.74818; 0207 m_ObjectNames << i18n("Mars") << i18n("Phobos") << i18n("Deimos"); 0208 m_objectDefaultFOVs << 0.00865 << 0.00002 << 0.00002; 0209 m_ObjectNames << i18n("Jupiter") << i18n("Ganymede") << i18n("Io") << i18n("Callisto") << i18n("Europa"); 0210 m_objectDefaultFOVs << 0.02 << 0.0005 << 0.0004 << 0.0005 << 0.0003; 0211 m_ObjectNames << i18n("Saturn") << i18n("Titan") << i18n("Mimas") << i18n("Enceladus") << i18n("Tethys") << i18n("Dione") << i18n("Rhea") << i18n("Hyperion") << i18n("Iapetus") << i18n("Phoebe"); 0212 m_objectDefaultFOVs << 0.02 << 0.0003 << 0.00002 << 0.00003 << 0.00007 << 0.00007 << 0.0001 << 0.00002 << 0.0001 << 0.00002; 0213 m_ObjectNames << i18n("Uranus") << i18n("Umbriel") << i18n("Ariel") << i18n("Miranda") << i18n("Titania") << i18n("Oberon"); 0214 m_objectDefaultFOVs << 0.00256 << 0.00004 << 0.00004 << 0.00002 << 0.00005 << 0.00005; 0215 m_ObjectNames << i18n("Neptune") << i18n("Triton"); 0216 m_objectDefaultFOVs << 0.00114 << 0.0001; 0217 0218 m_CurrentObjectIndex = m_ObjectNames.indexOf(obj); 0219 if (m_CurrentObjectIndex < 0) 0220 // Set to Saturn if current object is not in the list. 0221 m_CurrentObjectIndex = 13; 0222 m_ObjectName = m_ObjectNames.at(m_CurrentObjectIndex); 0223 0224 QComboBox *objectSelector = new QComboBox(this); 0225 objectSelector->addItems(m_ObjectNames); 0226 objectSelector->setToolTip(i18n("This allows you to select a new object/target for XPlanet to view")); 0227 selectorsLayout->addWidget(objectSelector); 0228 objectSelector->setCurrentIndex(m_CurrentObjectIndex); 0229 connect(objectSelector, SIGNAL(currentIndexChanged(int)), this, SLOT(updateXPlanetObject(int))); 0230 0231 m_CurrentOriginIndex = EARTH; 0232 m_OriginName = m_ObjectNames.at(EARTH); 0233 0234 selectorsLayout->addWidget(new QLabel(i18n("from"), this)); 0235 m_OriginSelector = new QComboBox(this); 0236 m_OriginSelector->addItems(m_ObjectNames); 0237 m_OriginSelector->setToolTip(i18n("This allows you to select a viewing location")); 0238 selectorsLayout->addWidget(m_OriginSelector); 0239 m_OriginSelector->setCurrentIndex(EARTH); 0240 connect(m_OriginSelector, SIGNAL(currentIndexChanged(int)), this, SLOT(updateXPlanetOrigin(int))); 0241 0242 m_lat = Options::xplanetLatitude().toDouble(); 0243 m_lon = Options::xplanetLongitude().toDouble(); 0244 m_Radius = 45; 0245 0246 selectorsLayout->addWidget(new QLabel(i18n("Location:"), this)); 0247 0248 m_PositionDisplay = new QLabel(this); 0249 m_PositionDisplay->setToolTip(i18n("XPlanet Latitude, Longitude, and object radius in %. This is only valid when viewing the object from the same object")); 0250 updatePositionDisplay(); 0251 m_PositionDisplay->setDisabled(true); 0252 selectorsLayout->addWidget(m_PositionDisplay); 0253 0254 QPushButton *resetXPlanetLocation = new QPushButton(this); 0255 resetXPlanetLocation->setIcon(QIcon::fromTheme("system-reboot")); 0256 resetXPlanetLocation->setAttribute(Qt::WA_LayoutUsesWidgetRect); 0257 resetXPlanetLocation->setMaximumSize(QSize(32, 32)); 0258 resetXPlanetLocation->setMinimumSize(QSize(32, 32)); 0259 resetXPlanetLocation->setToolTip(i18n("Reset XPlanet Location to the location specified in the XPlanet Options")); 0260 selectorsLayout->addWidget(resetXPlanetLocation); 0261 connect(resetXPlanetLocation, SIGNAL(clicked()), this, SLOT(resetLocation())); 0262 0263 m_FreeRotate = new QPushButton(this); 0264 m_FreeRotate->setIcon(QIcon::fromTheme("object-rotate-left")); 0265 m_FreeRotate->setAttribute(Qt::WA_LayoutUsesWidgetRect); 0266 m_FreeRotate->setMaximumSize(QSize(32, 32)); 0267 m_FreeRotate->setMinimumSize(QSize(32, 32)); 0268 m_FreeRotate->setCheckable(true); 0269 m_FreeRotate->setToolTip(i18n("Hover over target and freely rotate view with mouse in XPlanet Viewer")); 0270 selectorsLayout->addWidget(m_FreeRotate); 0271 connect(m_FreeRotate, SIGNAL(clicked()), this, SLOT(slotFreeRotate())); 0272 0273 QPushButton *reCenterB = new QPushButton(this); 0274 reCenterB->setIcon(QIcon::fromTheme("snap-bounding-box-center")); 0275 reCenterB->setAttribute(Qt::WA_LayoutUsesWidgetRect); 0276 reCenterB->setMaximumSize(QSize(32, 32)); 0277 reCenterB->setMinimumSize(QSize(32, 32)); 0278 reCenterB->setToolTip(i18n("Recenters the XPlanet image once it has been moved")); 0279 selectorsLayout->addWidget(reCenterB); 0280 connect(reCenterB, SIGNAL(clicked()), this, SLOT(reCenterXPlanet())); 0281 0282 QPushButton *saveB = new QPushButton(this); 0283 saveB->setIcon(QIcon::fromTheme("document-save")); 0284 saveB->setAttribute(Qt::WA_LayoutUsesWidgetRect); 0285 saveB->setMaximumSize(QSize(32, 32)); 0286 saveB->setMinimumSize(QSize(32, 32)); 0287 saveB->setToolTip(i18n("Save the image to disk")); 0288 selectorsLayout->addWidget(saveB); 0289 connect(saveB, SIGNAL(clicked()), this, SLOT(saveFileToDisk())); 0290 0291 QWidget *viewControlsWidget = new QWidget(this); 0292 QHBoxLayout *viewControlsLayout = new QHBoxLayout(viewControlsWidget); 0293 viewControlsLayout->setContentsMargins(0, 0, 0, 0); 0294 mainLayout->addWidget(viewControlsWidget); 0295 0296 viewControlsLayout->addWidget(new QLabel(i18n("FOV:"), this)); 0297 0298 m_FOVEdit = new NonLinearDoubleSpinBox(); 0299 m_FOVEdit->setDecimals(5); 0300 QList<double> possibleValues; 0301 possibleValues << 0; 0302 for(double i = .0001; i < 100; i *= 1.5) 0303 possibleValues << i; 0304 m_FOVEdit->setRecommendedValues(possibleValues); 0305 m_FOVEdit->setToolTip(i18n("Sets the FOV to the Specified value. Note: has no effect if hovering over object.")); 0306 viewControlsLayout->addWidget(m_FOVEdit); 0307 0308 if (Options::xplanetFOV()) 0309 m_FOV = KStars::Instance()->map()->fov(); 0310 else 0311 m_FOV = m_objectDefaultFOVs.at( m_CurrentObjectIndex); 0312 m_FOVEdit->setValue(m_FOV); 0313 0314 connect(m_FOVEdit, SIGNAL(valueChanged(double)), this, SLOT(updateXPlanetFOVEdit())); 0315 0316 m_KStarsFOV = new QPushButton(this); 0317 m_KStarsFOV->setIcon(QIcon::fromTheme("zoom-fit-width")); 0318 m_KStarsFOV->setAttribute(Qt::WA_LayoutUsesWidgetRect); 0319 m_KStarsFOV->setMaximumSize(QSize(32, 32)); 0320 m_KStarsFOV->setMinimumSize(QSize(32, 32)); 0321 m_KStarsFOV->setToolTip(i18n("Zoom to the current KStars FOV. Note: has no effect if hovering over object.")); 0322 viewControlsLayout->addWidget(m_KStarsFOV); 0323 connect(m_KStarsFOV, SIGNAL(clicked()), this, SLOT(setKStarsXPlanetFOV())); 0324 0325 m_setFOV = new QPushButton(this); 0326 m_setFOV->setIcon(QIcon::fromTheme("view-list-details")); 0327 m_setFOV->setAttribute(Qt::WA_LayoutUsesWidgetRect); 0328 m_setFOV->setMaximumSize(QSize(32, 32)); 0329 m_setFOV->setMinimumSize(QSize(32, 32)); 0330 m_setFOV->setToolTip(i18n("Zoom to a specific FOV. This has no effect when hovering over an object")); 0331 viewControlsLayout->addWidget(m_setFOV); 0332 connect(m_setFOV, SIGNAL(clicked()), this, SLOT(setFOVfromList())); 0333 0334 m_NoFOV = new QPushButton(this); 0335 m_NoFOV->setIcon(QIcon::fromTheme("system-reboot")); 0336 m_NoFOV->setAttribute(Qt::WA_LayoutUsesWidgetRect); 0337 m_NoFOV->setMaximumSize(QSize(32, 32)); 0338 m_NoFOV->setMinimumSize(QSize(32, 32)); 0339 m_NoFOV->setToolTip(i18n("Optimum FOV for the target, FOV parameter not specified. Note: has no effect if hovering over object.")); 0340 viewControlsLayout->addWidget(m_NoFOV); 0341 connect(m_NoFOV, SIGNAL(clicked()), this, SLOT(resetXPlanetFOV())); 0342 0343 m_Rotation = 0; 0344 0345 viewControlsLayout->addWidget(new QLabel(i18n("Rotation:"), this)); 0346 0347 m_RotateEdit = new QSpinBox(); 0348 0349 m_RotateEdit->setRange(-180, 180); 0350 m_RotateEdit->setValue(0); 0351 m_RotateEdit->setSingleStep(10); 0352 m_RotateEdit->setToolTip(i18n("Set the view rotation to the desired angle")); 0353 viewControlsLayout->addWidget(m_RotateEdit); 0354 connect(m_RotateEdit, SIGNAL(valueChanged(int)), this, SLOT(updateXPlanetRotationEdit())); 0355 0356 QPushButton *invertRotation = new QPushButton(this); 0357 invertRotation->setIcon(QIcon::fromTheme("object-flip-vertical")); 0358 invertRotation->setAttribute(Qt::WA_LayoutUsesWidgetRect); 0359 invertRotation->setMaximumSize(QSize(32, 32)); 0360 invertRotation->setMinimumSize(QSize(32, 32)); 0361 invertRotation->setToolTip(i18n("Rotate the view 180 degrees")); 0362 viewControlsLayout->addWidget(invertRotation); 0363 connect(invertRotation, SIGNAL(clicked()), this, SLOT(invertXPlanetRotation())); 0364 0365 QPushButton *resetRotation = new QPushButton(this); 0366 resetRotation->setIcon(QIcon::fromTheme("system-reboot")); 0367 resetRotation->setAttribute(Qt::WA_LayoutUsesWidgetRect); 0368 resetRotation->setMaximumSize(QSize(32, 32)); 0369 resetRotation->setMinimumSize(QSize(32, 32)); 0370 resetRotation->setToolTip(i18n("Reset view rotation to 0")); 0371 viewControlsLayout->addWidget(resetRotation); 0372 connect(resetRotation, SIGNAL(clicked()), this, SLOT(resetXPlanetRotation())); 0373 0374 QPushButton *optionsB = new QPushButton(this); 0375 optionsB->setIcon(QIcon::fromTheme("configure")); 0376 optionsB->setAttribute(Qt::WA_LayoutUsesWidgetRect); 0377 optionsB->setMaximumSize(QSize(32, 32)); 0378 optionsB->setMinimumSize(QSize(32, 32)); 0379 optionsB->setToolTip(i18n("Bring up XPlanet Options")); 0380 viewControlsLayout->addWidget(optionsB); 0381 connect(optionsB, SIGNAL(clicked()), KStars::Instance(), SLOT(slotViewOps())); 0382 0383 QPushButton *invertB = new QPushButton(this); 0384 invertB->setIcon(QIcon::fromTheme("edit-select-invert")); 0385 invertB->setAttribute(Qt::WA_LayoutUsesWidgetRect); 0386 invertB->setMaximumSize(QSize(32, 32)); 0387 invertB->setMinimumSize(QSize(32, 32)); 0388 invertB->setToolTip(i18n("Reverse colors of the image. This is useful to enhance contrast at times. This affects " 0389 "only the display and not the saving.")); 0390 viewControlsLayout->addWidget(invertB); 0391 connect(invertB, SIGNAL(clicked()), this, SLOT(invertColors())); 0392 0393 QWidget *timeWidget = new QWidget(this); 0394 QHBoxLayout *timeLayout = new QHBoxLayout(timeWidget); 0395 mainLayout->addWidget(timeWidget); 0396 timeLayout->setContentsMargins(0, 0, 0, 0); 0397 0398 m_XPlanetTime = KStarsData::Instance()->lt(); 0399 0400 QPushButton *setTime = new QPushButton(this); 0401 setTime->setIcon(QIcon::fromTheme("clock")); 0402 setTime->setAttribute(Qt::WA_LayoutUsesWidgetRect); 0403 setTime->setMaximumSize(QSize(32, 32)); 0404 setTime->setMinimumSize(QSize(32, 32)); 0405 setTime->setToolTip(i18n("Allows you to set the XPlanet time to a different date/time from KStars")); 0406 timeLayout->addWidget(setTime); 0407 connect(setTime, SIGNAL(clicked()), this, SLOT(setXPlanetTime())); 0408 0409 QPushButton *kstarsTime = new QPushButton(this); 0410 kstarsTime->setIcon(QIcon::fromTheme("system-reboot")); 0411 kstarsTime->setAttribute(Qt::WA_LayoutUsesWidgetRect); 0412 kstarsTime->setMaximumSize(QSize(32, 32)); 0413 kstarsTime->setMinimumSize(QSize(32, 32)); 0414 kstarsTime->setToolTip(i18n("Sets the XPlanet time to the current KStars time")); 0415 timeLayout->addWidget(kstarsTime); 0416 connect(kstarsTime, SIGNAL(clicked()), this, SLOT(setXPlanetTimetoKStarsTime())); 0417 0418 m_XPlanetTimeDisplay = new QLabel(this); 0419 m_XPlanetTimeDisplay->setToolTip(i18n("Current XPlanet Time")); 0420 timeLayout->addWidget(m_XPlanetTimeDisplay); 0421 0422 m_XPlanetTimeDisplay->setText(i18n("%1, %2", m_XPlanetTime.date().toString(), m_XPlanetTime.time().toString())); 0423 0424 m_TimeSlider = new QSlider(Qt::Horizontal, this); 0425 m_TimeSlider->setTracking(false); 0426 connect(m_TimeSlider, SIGNAL(sliderMoved(int)), this, SLOT(timeSliderDisplay(int))); 0427 timeLayout->addWidget(m_TimeSlider); 0428 m_TimeSlider->setRange(-100, 100); 0429 m_TimeSlider->setToolTip(i18n("This sets the time step from the current XPlanet time, good for viewing events")); 0430 connect(m_TimeSlider, SIGNAL(valueChanged(int)), this, SLOT(updateXPlanetTime(int))); 0431 0432 m_TimeEdit = new QSpinBox(this); 0433 m_TimeEdit->setRange(-10000, 10000); 0434 m_TimeEdit->setMaximumWidth(50); 0435 m_TimeEdit->setToolTip(i18n("This sets the time step from the current XPlanet time")); 0436 timeLayout->addWidget(m_TimeEdit); 0437 connect(m_TimeEdit, SIGNAL(valueChanged(int)), this, SLOT(updateXPlanetTimeEdit())); 0438 0439 m_CurrentTimeUnitIndex = MINS; 0440 m_TimeUnitsSelect = new QComboBox(this); 0441 timeLayout->addWidget(m_TimeUnitsSelect); 0442 m_TimeUnitsSelect->addItem(i18n("years")); 0443 m_TimeUnitsSelect->addItem(i18n("months")); 0444 m_TimeUnitsSelect->addItem(i18n("days")); 0445 m_TimeUnitsSelect->addItem(i18n("hours")); 0446 m_TimeUnitsSelect->addItem(i18n("minutes")); 0447 m_TimeUnitsSelect->addItem(i18n("seconds")); 0448 m_TimeUnitsSelect->setCurrentIndex(MINS); 0449 m_TimeUnitsSelect->setToolTip(i18n("Lets you change the units for the timestep in the animation")); 0450 connect(m_TimeUnitsSelect, SIGNAL(currentIndexChanged(int)), this, SLOT(updateXPlanetTimeUnits(int))); 0451 0452 m_XPlanetTimer = new QTimer(this); 0453 m_XPlanetTimer->setInterval(Options::xplanetAnimationDelay()); 0454 connect(m_XPlanetTimer, SIGNAL(timeout()), this, SLOT(incrementXPlanetTime())); 0455 0456 m_RunTime = new QPushButton(this); 0457 m_RunTime->setIcon(QIcon::fromTheme("media-playback-start")); 0458 m_RunTime->setAttribute(Qt::WA_LayoutUsesWidgetRect); 0459 m_RunTime->setCheckable(true); 0460 m_RunTime->setMaximumSize(QSize(32, 32)); 0461 m_RunTime->setMinimumSize(QSize(32, 32)); 0462 m_RunTime->setToolTip(i18n("Lets you run the animation")); 0463 timeLayout->addWidget(m_RunTime); 0464 connect(m_RunTime, SIGNAL(clicked()), this, SLOT(toggleXPlanetRun())); 0465 0466 QPushButton *resetTime = new QPushButton(this); 0467 resetTime->setIcon(QIcon::fromTheme("system-reboot")); 0468 resetTime->setAttribute(Qt::WA_LayoutUsesWidgetRect); 0469 resetTime->setMaximumSize(QSize(32, 32)); 0470 resetTime->setMinimumSize(QSize(32, 32)); 0471 resetTime->setToolTip(i18n("Resets the animation to 0 timesteps from the current XPlanet Time")); 0472 timeLayout->addWidget(resetTime); 0473 connect(resetTime, SIGNAL(clicked()), this, SLOT(resetXPlanetTime())); 0474 0475 m_View = new XPlanetImageLabel(page); 0476 m_View->setAutoFillBackground(false); 0477 m_Caption = new QLabel(page); 0478 m_Caption->setAutoFillBackground(true); 0479 m_Caption->setFrameShape(QFrame::StyledPanel); 0480 m_Caption->setText(m_ObjectName); 0481 // Add layout 0482 QVBoxLayout *vlay = new QVBoxLayout(page); 0483 vlay->setSpacing(0); 0484 vlay->setContentsMargins(0, 0, 0, 0); 0485 vlay->addWidget(m_View); 0486 vlay->addWidget(m_Caption); 0487 0488 0489 connect(m_View, SIGNAL(zoomIn()), this, SLOT(zoomInXPlanetFOV())); 0490 connect(m_View, SIGNAL(zoomOut()), this, SLOT(zoomOutXPlanetFOV())); 0491 connect(m_View, SIGNAL(changePosition(QPoint)), this, SLOT(changeXPlanetPosition(QPoint))); 0492 connect(m_View, SIGNAL(changeLocation(QPoint)), this, SLOT(changeXPlanetLocation(QPoint))); 0493 0494 //Reverse colors 0495 QPalette p = palette(); 0496 p.setColor(QPalette::Window, palette().color(QPalette::WindowText)); 0497 p.setColor(QPalette::WindowText, palette().color(QPalette::Window)); 0498 m_Caption->setPalette(p); 0499 m_View->setPalette(p); 0500 0501 #ifndef Q_OS_WIN 0502 if(Options::xplanetUseFIFO()) 0503 { 0504 connect(&watcherTimeout, SIGNAL(timeout()), &fifoImageLoadWatcher, SLOT(cancel())); 0505 connect(&fifoImageLoadWatcher, SIGNAL(finished()), this, SLOT(showImage())); 0506 } 0507 #endif 0508 0509 0510 #ifdef Q_OS_OSX 0511 QList<QPushButton *> qButtons = findChildren<QPushButton *>(); 0512 for (auto &button : qButtons) 0513 button->setAutoDefault(false); 0514 #endif 0515 updateXPlanetTime(0); 0516 #endif 0517 } 0518 0519 XPlanetImageViewer::~XPlanetImageViewer() 0520 { 0521 QApplication::restoreOverrideCursor(); 0522 } 0523 0524 void XPlanetImageViewer::startXplanet() 0525 { 0526 if(m_XPlanetRunning) 0527 return; 0528 0529 //This means something failed in the file output 0530 if(!setupOutputFile()) 0531 return; 0532 0533 QString xPlanetLocation = Options::xplanetPath(); 0534 #ifdef Q_OS_OSX 0535 if (Options::xplanetIsInternal()) 0536 xPlanetLocation = QCoreApplication::applicationDirPath() + QDir::separator() + "xplanet"; 0537 #endif 0538 0539 // If Options::xplanetPath() is empty, return 0540 if (xPlanetLocation.isEmpty()) 0541 { 0542 KSNotification::error(i18n("Xplanet binary path is empty in config panel.")); 0543 return; 0544 } 0545 0546 // If Options::xplanetPath() does not exist, return 0547 const QFileInfo xPlanetLocationInfo(xPlanetLocation); 0548 if (!xPlanetLocationInfo.exists() || !xPlanetLocationInfo.isExecutable()) 0549 { 0550 KSNotification::error(i18n("The configured Xplanet binary does not exist or is not executable.")); 0551 return; 0552 } 0553 0554 // Create xplanet process 0555 QProcess *xplanetProc = new QProcess(this); 0556 0557 // Add some options 0558 QStringList args; 0559 0560 //This specifies the object to be viewed 0561 args << "-body" << m_ObjectName.toLower(); 0562 //This is the date and time requested 0563 args << "-date" << m_Date; 0564 //This is the glare from the sun 0565 args << "-glare" << Options::xplanetGlare(); 0566 args << "-base_magnitude" << Options::xplanetMagnitude(); 0567 //This is the correction for light's travel time. 0568 args << "-light_time"; 0569 0570 args << "-geometry" << QString::number(Options::xplanetWidth()) + 'x' + QString::number(Options::xplanetHeight()); 0571 0572 if(m_FOV != 0) 0573 args << "-fov" << QString::number(m_FOV); 0574 //Need to convert to locale for places that don't use decimals?? 0575 //args << "-fov" << fov.setNum(fov());//.replace('.', ','); 0576 0577 //This rotates the view for different object angles 0578 args << "-rotate" << QString::number(m_Rotation); 0579 0580 if (Options::xplanetConfigFile()) 0581 args << "-config" << Options::xplanetConfigFilePath(); 0582 if (Options::xplanetStarmap()) 0583 args << "-starmap" << Options::xplanetStarmapPath(); 0584 if (Options::xplanetArcFile()) 0585 args << "-arc_file" << Options::xplanetArcFilePath(); 0586 if (!m_File.fileName().isEmpty()) 0587 args << "-output" << m_File.fileName() << "-quality" << Options::xplanetQuality(); 0588 0589 // Labels 0590 if (Options::xplanetLabel()) 0591 { 0592 args << "-fontsize" << Options::xplanetFontSize() << "-color" 0593 << "0x" + Options::xplanetColor().mid(1) << "-date_format" << Options::xplanetDateFormat(); 0594 0595 if (Options::xplanetLabelGMT()) 0596 args << "-gmtlabel"; 0597 else 0598 args << "-label"; 0599 if (!Options::xplanetLabelString().isEmpty()) 0600 args << "-label_string" 0601 << "\"" + Options::xplanetLabelString() + "\""; 0602 if (Options::xplanetLabelTL()) 0603 args << "-labelpos" 0604 << "+15+15"; 0605 else if (Options::xplanetLabelTR()) 0606 args << "-labelpos" 0607 << "-15+15"; 0608 else if (Options::xplanetLabelBR()) 0609 args << "-labelpos" 0610 << "-15-15"; 0611 else if (Options::xplanetLabelBL()) 0612 args << "-labelpos" 0613 << "+15-15"; 0614 } 0615 0616 // Markers 0617 if (Options::xplanetMarkerFile()) 0618 args << "-marker_file" << Options::xplanetMarkerFilePath(); 0619 if (Options::xplanetMarkerBounds()) 0620 args << "-markerbounds" << Options::xplanetMarkerBoundsPath(); 0621 0622 // Position 0623 // This sets the position from which the planet is viewed. 0624 // Note that setting Latitude and Longitude means that position above the SAME object 0625 0626 if(m_CurrentObjectIndex == m_CurrentOriginIndex) 0627 { 0628 if (Options::xplanetRandom()) 0629 args << "-random"; 0630 else 0631 args << "-latitude" << QString::number(m_lat) << "-longitude" << QString::number(m_lon) << "-radius" << QString::number(m_Radius); 0632 } 0633 else 0634 args << "-origin" << m_OriginName; 0635 0636 //Centering 0637 //This allows you to recenter the xplanet view 0638 0639 args << "-center" << "+" + QString::number(Options::xplanetWidth() / 2 + center.x()) + "+" + QString::number(Options::xplanetHeight() / 2 + center.y()); 0640 0641 // Projection 0642 if (Options::xplanetProjection()) 0643 { 0644 switch (Options::xplanetProjection()) 0645 { 0646 case 1: 0647 args << "-projection" 0648 << "ancient"; 0649 break; 0650 case 2: 0651 args << "-projection" 0652 << "azimuthal"; 0653 break; 0654 case 3: 0655 args << "-projection" 0656 << "bonne"; 0657 break; 0658 case 4: 0659 args << "-projection" 0660 << "gnomonic"; 0661 break; 0662 case 5: 0663 args << "-projection" 0664 << "hemisphere"; 0665 break; 0666 case 6: 0667 args << "-projection" 0668 << "lambert"; 0669 break; 0670 case 7: 0671 args << "-projection" 0672 << "mercator"; 0673 break; 0674 case 8: 0675 args << "-projection" 0676 << "mollweide"; 0677 break; 0678 case 9: 0679 args << "-projection" 0680 << "orthographic"; 0681 break; 0682 case 10: 0683 args << "-projection" 0684 << "peters"; 0685 break; 0686 case 11: 0687 args << "-projection" 0688 << "polyconic"; 0689 break; 0690 case 12: 0691 args << "-projection" 0692 << "rectangular"; 0693 break; 0694 case 13: 0695 args << "-projection" 0696 << "tsc"; 0697 break; 0698 default: 0699 break; 0700 } 0701 if (Options::xplanetBackground()) 0702 { 0703 if (Options::xplanetBackgroundImage()) 0704 args << "-background" << Options::xplanetBackgroundImagePath(); 0705 else 0706 args << "-background" 0707 << "0x" + Options::xplanetBackgroundColorValue().mid(1); 0708 } 0709 } 0710 0711 #ifdef Q_OS_OSX 0712 QString searchDir = QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kstars", QStandardPaths::LocateDirectory) + QDir::separator() + "xplanet"; 0713 args << "-searchdir" << searchDir; 0714 #endif 0715 0716 #ifdef Q_OS_WIN 0717 QString searchDir = xPlanetLocationInfo.dir().absolutePath() + QDir::separator() + "xplanet"; 0718 args << "-searchdir" << searchDir; 0719 #endif 0720 0721 //This prevents it from running forever. 0722 args << "-num_times" << "1"; 0723 0724 m_XPlanetRunning = true; 0725 m_ImageLoadSucceeded = false; //This will be set to true if it works. 0726 uint32_t timeout = Options::xplanetTimeout(); 0727 0728 //FIFO files don't work on windows 0729 #ifndef Q_OS_WIN 0730 if(Options::xplanetUseFIFO()) 0731 { 0732 fifoImageLoadWatcher.setFuture(QtConcurrent::run(this, &XPlanetImageViewer::loadImage)); 0733 watcherTimeout.setSingleShot(true); 0734 watcherTimeout.start(timeout); 0735 } 0736 #endif 0737 0738 xplanetProc->start(xPlanetLocation, args); 0739 0740 //Uncomment to print the XPlanet commands to the console 0741 // qDebug() << Q_FUNC_INFO << "Run:" << xplanetProc->program() << args.join(" "); 0742 0743 bool XPlanetSucceeded = xplanetProc->waitForFinished(timeout); 0744 m_XPlanetRunning = false; 0745 xplanetProc->kill(); //In case it timed out 0746 xplanetProc->deleteLater(); 0747 if(XPlanetSucceeded) 0748 { 0749 if(m_FOV == 0) 0750 m_Caption->setText(i18n("XPlanet View: %1 from %2 on %3", m_ObjectName, m_OriginName, m_DateText)); 0751 else 0752 m_Caption->setText(i18n("XPlanet View: %1 from %2 on %3 at FOV: %4 deg", m_ObjectName, m_OriginName, m_DateText, m_FOV)); 0753 #ifdef Q_OS_WIN 0754 loadImage(); //This will also set imageLoadSucceeded based on whether it worked. 0755 #else 0756 if(Options::xplanetUseFIFO()) 0757 return; //The loading of the image is handled with the watcher 0758 else 0759 loadImage(); //This will also set imageLoadSucceeded based on whether it worked. 0760 #endif 0761 0762 if(m_ImageLoadSucceeded) 0763 showImage(); 0764 else 0765 { 0766 KSNotification::error(i18n("Loading of the image of object %1 failed.", m_ObjectName)); 0767 } 0768 } 0769 else 0770 { 0771 KStars::Instance()->statusBar()->showMessage(i18n("XPlanet failed to generate the image for object %1 before the timeout expired.", m_ObjectName)); 0772 #ifndef Q_OS_WIN 0773 if(Options::xplanetUseFIFO()) 0774 fifoImageLoadWatcher.cancel(); 0775 #endif 0776 } 0777 } 0778 0779 bool XPlanetImageViewer::setupOutputFile() 0780 { 0781 #ifndef Q_OS_WIN 0782 if(Options::xplanetUseFIFO()) 0783 { 0784 if(m_File.fileName().contains("xplanetfifo") && m_File.exists()) 0785 return true; 0786 QDir kstarsTempDir(KSPaths::writableLocation(QStandardPaths::TempLocation) + QDir::separator() + qAppName()); 0787 kstarsTempDir.mkpath("."); 0788 m_File.setFileName(kstarsTempDir.filePath(QString("xplanetfifo%1.png").arg(QUuid::createUuid().toString().mid(1, 8)).toLatin1())); 0789 if (mkfifo(m_File.fileName().toLatin1(), S_IRUSR | S_IWUSR) < 0) 0790 { 0791 KSNotification::error(i18n("Error making FIFO file %1: %2.", m_File.fileName(), strerror(errno))); 0792 return false; 0793 } 0794 return true; 0795 } 0796 #endif 0797 0798 //If the user is using windows or has not selected to use FIFO, it uses files in the KStars data directory. 0799 QDir xPlanetDirPath(KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + QDir::separator() + "xplanet"); 0800 xPlanetDirPath.mkpath("."); 0801 m_File.setFileName(xPlanetDirPath.filePath(m_ObjectName + ".png")); 0802 return true; 0803 } 0804 0805 void XPlanetImageViewer::zoomInXPlanetFOV() 0806 { 0807 if(m_CurrentObjectIndex == m_CurrentOriginIndex) 0808 { 0809 m_Radius += 5; 0810 updatePositionDisplay(); 0811 startXplanet(); 0812 } 0813 else 0814 { 0815 m_FOVEdit->stepDown(); 0816 startXplanet(); 0817 } 0818 0819 } 0820 0821 void XPlanetImageViewer::zoomOutXPlanetFOV() 0822 { 0823 if(m_CurrentObjectIndex == m_CurrentOriginIndex) 0824 { 0825 if(m_Radius > 0) 0826 { 0827 m_Radius -= 5; 0828 updatePositionDisplay(); 0829 startXplanet(); 0830 } 0831 } 0832 else 0833 { 0834 m_FOVEdit->stepUp(); 0835 startXplanet(); 0836 } 0837 0838 } 0839 0840 void XPlanetImageViewer::updatePositionDisplay() 0841 { 0842 m_PositionDisplay->setText(i18n("%1, %2, %3", QString::number(m_lat), QString::number(m_lon), QString::number(m_Radius))); 0843 } 0844 0845 void XPlanetImageViewer::updateXPlanetTime(int timeShift) 0846 { 0847 0848 KStarsDateTime shiftedXPlanetTime; 0849 switch(m_CurrentTimeUnitIndex) 0850 { 0851 case YEARS: 0852 shiftedXPlanetTime = m_XPlanetTime.addDays(timeShift * 365); 0853 break; 0854 0855 case MONTHS: 0856 shiftedXPlanetTime = m_XPlanetTime.addDays(timeShift * 30); 0857 break; 0858 0859 case DAYS: 0860 shiftedXPlanetTime = m_XPlanetTime.addDays(timeShift); 0861 break; 0862 0863 case HOURS: 0864 shiftedXPlanetTime = m_XPlanetTime.addSecs(timeShift * 3600); 0865 break; 0866 0867 case MINS: 0868 shiftedXPlanetTime = m_XPlanetTime.addSecs(timeShift * 60); 0869 break; 0870 0871 case SECS: 0872 shiftedXPlanetTime = m_XPlanetTime.addSecs(timeShift); 0873 break; 0874 } 0875 0876 setXPlanetDate(shiftedXPlanetTime); 0877 m_DateText = i18n("%1, %2", shiftedXPlanetTime.date().toString(), shiftedXPlanetTime.time().toString()); 0878 if(m_TimeEdit->value() != timeShift) 0879 m_TimeEdit->setValue(timeShift); 0880 else 0881 startXplanet(); 0882 } 0883 0884 void XPlanetImageViewer::updateXPlanetObject(int objectIndex) 0885 { 0886 center = QPoint(0, 0); 0887 m_CurrentObjectIndex = objectIndex; 0888 m_ObjectName = m_ObjectNames.at(objectIndex); 0889 0890 setWindowTitle(i18nc("@title:window", "XPlanet Solar System Simulator: %1", m_ObjectName)); 0891 if(m_FreeRotate->isChecked()) 0892 m_OriginSelector->setCurrentIndex(m_CurrentObjectIndex); 0893 if(m_CurrentObjectIndex == m_CurrentOriginIndex) 0894 startXplanet(); 0895 else 0896 resetXPlanetFOV(); 0897 } 0898 0899 void XPlanetImageViewer::updateXPlanetOrigin(int originIndex) 0900 { 0901 center = QPoint(0, 0); 0902 m_CurrentOriginIndex = originIndex; 0903 m_OriginName = m_ObjectNames.at(originIndex); 0904 if(m_CurrentObjectIndex == m_CurrentOriginIndex) 0905 m_FreeRotate->setChecked(true); 0906 else 0907 m_FreeRotate->setChecked(false); 0908 updateStates();//This will update the disabled/enabled states 0909 startXplanet(); 0910 } 0911 0912 void XPlanetImageViewer::changeXPlanetLocation(QPoint delta) 0913 { 0914 if(m_CurrentObjectIndex == m_CurrentOriginIndex) 0915 { 0916 double newLon = m_lon + delta.x(); 0917 double newLat = m_lat + delta.y(); 0918 0919 newLat = qBound(-90.0, newLat, 90.0); 0920 0921 m_lon = newLon; 0922 m_lat = newLat; 0923 0924 updatePositionDisplay(); 0925 startXplanet(); 0926 } 0927 } 0928 0929 void XPlanetImageViewer::changeXPlanetPosition(QPoint delta) 0930 { 0931 center.setX(center.x() + delta.x()); 0932 center.setY(center.y() + delta.y()); 0933 startXplanet(); 0934 } 0935 0936 void XPlanetImageViewer::reCenterXPlanet() 0937 { 0938 center = QPoint(0, 0); 0939 startXplanet(); 0940 } 0941 0942 void XPlanetImageViewer::resetLocation() 0943 { 0944 m_lat = Options::xplanetLatitude().toDouble(); 0945 m_lon = Options::xplanetLongitude().toDouble(); 0946 m_Radius = 45; 0947 updatePositionDisplay(); 0948 startXplanet(); 0949 } 0950 0951 void XPlanetImageViewer::slotFreeRotate() 0952 { 0953 if(m_FreeRotate->isChecked()) 0954 m_OriginSelector->setCurrentIndex(m_CurrentObjectIndex); 0955 else 0956 m_OriginSelector->setCurrentIndex(EARTH); 0957 } 0958 0959 void XPlanetImageViewer::updateStates() 0960 { 0961 if(m_FreeRotate->isChecked()) 0962 { 0963 m_FOVEdit->setDisabled(true); 0964 m_KStarsFOV->setDisabled(true); 0965 m_NoFOV->setDisabled(true); 0966 0967 m_PositionDisplay->setDisabled(false); 0968 } 0969 else 0970 { 0971 m_FOVEdit->setDisabled(false); 0972 m_KStarsFOV->setDisabled(false); 0973 m_NoFOV->setDisabled(false); 0974 0975 m_PositionDisplay->setDisabled(true); 0976 } 0977 } 0978 0979 void XPlanetImageViewer::setXPlanetDate(KStarsDateTime time) 0980 { 0981 //Note Xplanet uses UT time for everything but we want the labels to all be LT 0982 KStarsDateTime utTime = KStarsData::Instance()->geo()->LTtoUT(time); 0983 m_Date = utTime.toString(Qt::ISODate) 0984 .replace("-", QString("")) 0985 .replace("T", ".") 0986 .replace(":", QString("")) 0987 .replace("Z", QString("")); 0988 } 0989 0990 void XPlanetImageViewer::updateXPlanetTimeUnits(int units) 0991 { 0992 m_CurrentTimeUnitIndex = units; 0993 updateXPlanetTimeEdit(); 0994 } 0995 0996 void XPlanetImageViewer::updateXPlanetTimeEdit() 0997 { 0998 if(m_TimeSlider->isSliderDown()) 0999 return; 1000 int timeShift = m_TimeEdit->value(); 1001 if(m_TimeSlider->value() != timeShift) 1002 { 1003 1004 if(timeShift > m_TimeSlider->maximum() + 100) 1005 m_TimeSlider->setMaximum(timeShift); 1006 if(timeShift < m_TimeSlider->minimum() - 100) 1007 m_TimeSlider->setMinimum(timeShift); 1008 m_TimeSlider->setValue(timeShift); 1009 } 1010 else 1011 updateXPlanetTime(timeShift); 1012 } 1013 1014 void XPlanetImageViewer::timeSliderDisplay(int timeShift) 1015 { 1016 m_TimeEdit->setValue(timeShift); 1017 } 1018 1019 void XPlanetImageViewer::incrementXPlanetTime() 1020 { 1021 if(!m_XPlanetRunning) 1022 { 1023 int timeShift = m_TimeEdit->value(); 1024 if(m_TimeSlider->maximum() <= timeShift) 1025 m_TimeSlider->setMaximum(timeShift + 100); 1026 if(m_TimeEdit->maximum() <= timeShift) 1027 m_TimeEdit->setMaximum(timeShift + 100); 1028 m_TimeSlider->setValue(timeShift + 1); 1029 } 1030 } 1031 1032 void XPlanetImageViewer::setXPlanetTime() 1033 { 1034 QPointer<TimeDialog> timedialog = new TimeDialog(m_XPlanetTime, KStarsData::Instance()->geo(), this); 1035 if (timedialog->exec() == QDialog::Accepted) 1036 { 1037 m_XPlanetTime = timedialog->selectedDateTime(); 1038 m_XPlanetTimeDisplay->setText(i18n("%1, %2", m_XPlanetTime.date().toString(), m_XPlanetTime.time().toString())); 1039 int timeShift = 0; 1040 m_TimeSlider->setRange(-100, 100); 1041 if(m_TimeSlider->value() != timeShift) 1042 m_TimeSlider->setValue(timeShift); 1043 else 1044 updateXPlanetTime(timeShift); 1045 } 1046 } 1047 1048 void XPlanetImageViewer::setXPlanetTimetoKStarsTime() 1049 { 1050 m_XPlanetTime = KStarsData::Instance()->lt(); 1051 m_XPlanetTimeDisplay->setText(i18n("%1, %2", m_XPlanetTime.date().toString(), m_XPlanetTime.time().toString())); 1052 int timeShift = 0; 1053 m_TimeSlider->setRange(-100, 100); 1054 if(m_TimeSlider->value() != timeShift) 1055 m_TimeSlider->setValue(timeShift); 1056 else 1057 updateXPlanetTime(timeShift); 1058 } 1059 1060 void XPlanetImageViewer::resetXPlanetTime() 1061 { 1062 int timeShift = 0; 1063 m_TimeSlider->setRange(-100, 100); 1064 if(m_TimeSlider->value() != timeShift) 1065 m_TimeSlider->setValue(timeShift); 1066 else 1067 updateXPlanetTime(timeShift); 1068 } 1069 1070 void XPlanetImageViewer::toggleXPlanetRun() 1071 { 1072 if(m_XPlanetTimer->isActive()) 1073 { 1074 m_XPlanetTimer->stop(); 1075 #ifndef Q_OS_WIN 1076 if(Options::xplanetUseFIFO()) 1077 fifoImageLoadWatcher.cancel(); 1078 #endif 1079 } 1080 else 1081 { 1082 m_XPlanetTimer->setInterval(Options::xplanetAnimationDelay()); 1083 m_XPlanetTimer->start(); 1084 } 1085 } 1086 1087 void XPlanetImageViewer::updateXPlanetFOVEdit() 1088 { 1089 m_FOV = m_FOVEdit->value(); 1090 startXplanet(); 1091 } 1092 1093 void XPlanetImageViewer::resetXPlanetFOV() 1094 { 1095 m_FOV = m_objectDefaultFOVs.at(m_CurrentObjectIndex); 1096 m_FOVEdit->setValue(m_FOV); 1097 startXplanet(); 1098 } 1099 1100 void XPlanetImageViewer::setKStarsXPlanetFOV() 1101 { 1102 m_FOV = KStars::Instance()->map()->fov(); 1103 m_FOVEdit->setValue(m_FOV); 1104 startXplanet(); 1105 } 1106 void XPlanetImageViewer::setFOVfromList() 1107 { 1108 if (!KStarsData::Instance()->getAvailableFOVs().isEmpty()) 1109 { 1110 // Ask the user to choose from a list of available FOVs. 1111 QMap<QString, const FOV *> nameToFovMap; 1112 for (const FOV *f : KStarsData::Instance()->getAvailableFOVs()) 1113 { 1114 nameToFovMap.insert(f->name(), f); 1115 } 1116 bool ok = false; 1117 const FOV *fov = nullptr; 1118 fov = nameToFovMap[QInputDialog::getItem(this, i18n("Choose a field-of-view"), 1119 i18n("FOV to render in XPlanet:"), nameToFovMap.keys(), 0, 1120 false, &ok)]; 1121 if (ok) 1122 { 1123 m_FOV = fov->sizeX() / 60 ; //Converting from arcmin to degrees 1124 m_FOVEdit->setValue(m_FOV); 1125 startXplanet(); 1126 } 1127 } 1128 } 1129 1130 void XPlanetImageViewer::updateXPlanetRotationEdit() 1131 { 1132 m_Rotation = m_RotateEdit->value(); 1133 startXplanet(); 1134 } 1135 1136 void XPlanetImageViewer::resetXPlanetRotation() 1137 { 1138 m_RotateEdit->setValue(0); 1139 } 1140 1141 void XPlanetImageViewer::invertXPlanetRotation() 1142 { 1143 m_RotateEdit->setValue(180); 1144 } 1145 1146 bool XPlanetImageViewer::loadImage() 1147 { 1148 #ifndef KSTARS_LITE 1149 1150 if (!m_Image.load(m_File.fileName())) 1151 { 1152 m_ImageLoadSucceeded = false; 1153 return false; 1154 } 1155 m_ImageLoadSucceeded = true; 1156 return true; 1157 #else 1158 imageLoadSucceeded = false; 1159 return false; 1160 #endif 1161 } 1162 1163 bool XPlanetImageViewer::showImage() 1164 { 1165 #ifndef KSTARS_LITE 1166 1167 //If the image is larger than screen width and/or screen height, 1168 //shrink it to fit the screen 1169 QRect deskRect = QGuiApplication::primaryScreen()->geometry(); 1170 int w = deskRect.width(); // screen width 1171 int h = deskRect.height(); // screen height 1172 1173 if (m_Image.width() <= w && m_Image.height() > h) //Window is taller than desktop 1174 m_Image = m_Image.scaled(int(m_Image.width() * h / m_Image.height()), h); 1175 else if (m_Image.height() <= h && m_Image.width() > w) //window is wider than desktop 1176 m_Image = m_Image.scaled(w, int(m_Image.height() * w / m_Image.width())); 1177 else if (m_Image.width() > w && m_Image.height() > h) //window is too tall and too wide 1178 { 1179 //which needs to be shrunk least, width or height? 1180 float fx = float(w) / float(m_Image.width()); 1181 float fy = float(h) / float(m_Image.height()); 1182 if (fx > fy) //width needs to be shrunk less, so shrink to fit in height 1183 m_Image = m_Image.scaled(int(m_Image.width() * fy), h); 1184 else //vice versa 1185 m_Image = m_Image.scaled(w, int(m_Image.height() * fx)); 1186 } 1187 const bool initialLoad = !isVisible(); 1188 1189 show(); // hide is default 1190 1191 m_View->setImage(m_Image); 1192 w = m_Image.width(); 1193 1194 //If the caption is wider than the image, set the window size 1195 //to fit the caption 1196 if (m_Caption->width() > w) 1197 w = m_Caption->width(); 1198 if(initialLoad) 1199 resize(w, m_Image.height()); 1200 else 1201 { 1202 m_View->refreshImage(); 1203 } 1204 1205 update(); 1206 show(); 1207 1208 return true; 1209 #else 1210 return false; 1211 #endif 1212 } 1213 1214 void XPlanetImageViewer::saveFileToDisk() 1215 { 1216 #ifndef KSTARS_LITE 1217 QFileDialog saveDialog(KStars::Instance(), i18nc("@title:window", "Save Image"), m_LastFile); 1218 saveDialog.setDefaultSuffix("png"); 1219 saveDialog.setAcceptMode(QFileDialog::AcceptSave); 1220 saveDialog.exec(); 1221 1222 if(saveDialog.result() == QFileDialog::Rejected) 1223 return; 1224 if(saveDialog.selectedFiles().isEmpty()) 1225 return; 1226 QString newFileName = saveDialog.selectedFiles().first(); 1227 if(newFileName.isEmpty()) 1228 return; 1229 1230 m_LastFile = newFileName; 1231 1232 saveFile(newFileName); 1233 1234 #endif 1235 } 1236 1237 void XPlanetImageViewer::saveFile(const QString &fileName) 1238 { 1239 #ifndef KSTARS_LITE 1240 1241 if (! m_Image.save(fileName, "png")) 1242 { 1243 KSNotification::error(i18n("Saving of the image to %1 failed.", fileName)); 1244 } 1245 else 1246 KStars::Instance()->statusBar()->showMessage(i18n("Saved image to %1", fileName)); 1247 #endif 1248 } 1249 1250 void XPlanetImageViewer::invertColors() 1251 { 1252 #ifndef KSTARS_LITE 1253 // Invert colors 1254 m_View->invertPixels(); 1255 m_View->update(); 1256 #endif 1257 } 1258