Kstars

xplanetimageviewer.cpp
1/*
2 SPDX-FileCopyrightText: Thomas Kabelmann
3 SPDX-FileCopyrightText: 2018 Robert Lancaster <rlancaste@gmail.com>
4
5 SPDX-License-Identifier: GPL-2.0-or-later
6*/
7
8#include "xplanetimageviewer.h"
9#include "Options.h"
10#include "dialogs/timedialog.h"
11#include "ksnotification.h"
12
13#include <QtConcurrent>
14
15#ifndef KSTARS_LITE
16#include "kstars.h"
17#endif
18
19#ifndef KSTARS_LITE
20#include <KMessageBox>
21#endif
22
23#include <QFileDialog>
24#include <QPainter>
25#include <QResizeEvent>
26#include <QStatusBar>
27#include <QTemporaryFile>
28#include <QVBoxLayout>
29#include <QPushButton>
30#include <QApplication>
31#include <QScreen>
32#include <QSlider>
33#include "skymap.h"
34#include "kspaths.h"
35#include "fov.h"
36
37#include <QUuid>
38#include <sys/stat.h>
39#include <QInputDialog>
40
41typedef enum
42{
43 SUN, MERCURY, VENUS,
44 EARTH, MOON,
45 MARS, PHOBOS, DEIMOS,
46 JUPITER, GANYMEDE, IO, CALLISTO, EUROPA,
47 SATURN, TITAN, MIMAS, ENCELADUS, TETHYS, DIONE, RHEA, HYPERION, IAPETUS, PHOEBE,
48 URANUS, UMBRIEL, ARIEL, MIRANDA, TITANIA, OBERON,
49 NEPTUNE, TRITON
50} objects;
51
52XPlanetImageLabel::XPlanetImageLabel(QWidget *parent) : QFrame(parent)
53{
54#ifndef KSTARS_LITE
55 grabGesture(Qt::PinchGesture);
57 setFrameStyle(QFrame::StyledPanel | QFrame::Plain);
58 setLineWidth(2);
59#endif
60}
61
62void XPlanetImageLabel::setImage(const QImage &img)
63{
64#ifndef KSTARS_LITE
65 m_Image = img;
66 m_Pix = QPixmap::fromImage(m_Image);
67#endif
68}
69
70void XPlanetImageLabel::invertPixels()
71{
72#ifndef KSTARS_LITE
73 m_Image.invertPixels();
74 m_Pix = QPixmap::fromImage(m_Image.scaled(width(), height(), Qt::KeepAspectRatio));
75#endif
76}
77
78void XPlanetImageLabel::paintEvent(QPaintEvent *)
79{
80#ifndef KSTARS_LITE
81 QPainter p;
82 p.begin(this);
83 int x = 0;
84 if (m_Pix.width() < width())
85 x = (width() - m_Pix.width()) / 2;
86 p.drawPixmap(x, 0, m_Pix);
87 p.end();
88#endif
89}
90
91void XPlanetImageLabel::resizeEvent(QResizeEvent *event)
92{
93 if (event->size() == m_Pix.size())
94 return;
95
96 m_Pix = QPixmap::fromImage(m_Image.scaled(event->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
97}
98
99void XPlanetImageLabel::refreshImage()
100{
102 update();
103}
104
105void XPlanetImageLabel::wheelEvent(QWheelEvent *e)
106{
107 //This attempts to send the wheel event back to the Scroll Area if it was taken from a trackpad
108 //It should still do the zoom if it is a mouse wheel
110 {
112 }
113 else
114 {
115 if (e->angleDelta().y() > 0)
116 emit zoomIn();
117 else if (e->angleDelta().y() < 0)
118 emit zoomOut();
119 e->accept();
120 }
121}
122
123bool XPlanetImageLabel::event(QEvent *event)
124{
125 if (event->type() == QEvent::Gesture)
126 return gestureEvent(dynamic_cast<QGestureEvent *>(event));
127 return QFrame::event(event);
128}
129
130bool XPlanetImageLabel::gestureEvent(QGestureEvent *event)
131{
132 if (QGesture *pinch = event->gesture(Qt::PinchGesture))
133 pinchTriggered(dynamic_cast<QPinchGesture *>(pinch));
134 return true;
135}
136
137
138void XPlanetImageLabel::pinchTriggered(QPinchGesture *gesture)
139{
140 if (gesture->totalScaleFactor() > 1)
141 emit zoomIn();
142 else
143 emit zoomOut();
144}
145
146
147void XPlanetImageLabel::mousePressEvent(QMouseEvent *e)
148{
149 m_MouseButtonDown = true;
150 m_LastMousePoint = e->globalPos();
151 e->accept();
152}
153
154void XPlanetImageLabel::mouseReleaseEvent(QMouseEvent *e)
155{
156 m_MouseButtonDown = false;
157 e->accept();
158}
159
160void XPlanetImageLabel::mouseMoveEvent(QMouseEvent *e)
161{
162 if(m_MouseButtonDown)
163 {
164 QPoint newPoint = e->globalPos();
165 int dx = newPoint.x() - m_LastMousePoint.x();
166 int dy = newPoint.y() - m_LastMousePoint.y();
167 if(e->buttons() & Qt::RightButton)
168 emit changeLocation(QPoint(dx, dy));
169 if(e->buttons() & Qt::LeftButton)
170 emit changePosition(QPoint(dx, dy));
171 m_LastMousePoint = newPoint;
172 }
173 e->accept();
174}
175
177{
178#ifndef KSTARS_LITE
179 m_LastFile = QDir::homePath();
180
181#ifdef Q_OS_MACOS
183#endif
185 setModal(false);
186 setWindowTitle(i18nc("@title:window", "XPlanet Solar System Simulator: %1", obj));
187
188 setXPlanetDate(KStarsData::Instance()->ut());
189
190 // Create widget
191 QFrame *page = new QFrame(this);
192
193 //setMainWidget( page );
194 QVBoxLayout *mainLayout = new QVBoxLayout(this);
195 mainLayout->addWidget(page);
196 setLayout(mainLayout);
197
198 QWidget *selectorsWidget = new QWidget(this);
199 QHBoxLayout *selectorsLayout = new QHBoxLayout(selectorsWidget);
200 selectorsLayout->setContentsMargins(0, 0, 0, 0);
201 mainLayout->addWidget(selectorsWidget);
202
203 m_ObjectNames << i18n("Sun") << i18n("Mercury") << i18n("Venus");
204 m_objectDefaultFOVs << 0.74818 << 0.004 << 0.02;
205 m_ObjectNames << i18n("Earth") << i18n("Moon");
206 m_objectDefaultFOVs << 1.0 << 0.74818;
207 m_ObjectNames << i18n("Mars") << i18n("Phobos") << i18n("Deimos");
208 m_objectDefaultFOVs << 0.00865 << 0.00002 << 0.00002;
209 m_ObjectNames << i18n("Jupiter") << i18n("Ganymede") << i18n("Io") << i18n("Callisto") << i18n("Europa");
210 m_objectDefaultFOVs << 0.02 << 0.0005 << 0.0004 << 0.0005 << 0.0003;
211 m_ObjectNames << i18n("Saturn") << i18n("Titan") << i18n("Mimas") << i18n("Enceladus") << i18n("Tethys") << i18n("Dione") << i18n("Rhea") << i18n("Hyperion") << i18n("Iapetus") << i18n("Phoebe");
212 m_objectDefaultFOVs << 0.02 << 0.0003 << 0.00002 << 0.00003 << 0.00007 << 0.00007 << 0.0001 << 0.00002 << 0.0001 << 0.00002;
213 m_ObjectNames << i18n("Uranus") << i18n("Umbriel") << i18n("Ariel") << i18n("Miranda") << i18n("Titania") << i18n("Oberon");
214 m_objectDefaultFOVs << 0.00256 << 0.00004 << 0.00004 << 0.00002 << 0.00005 << 0.00005;
215 m_ObjectNames << i18n("Neptune") << i18n("Triton");
216 m_objectDefaultFOVs << 0.00114 << 0.0001;
217
218 m_CurrentObjectIndex = m_ObjectNames.indexOf(obj);
219 if (m_CurrentObjectIndex < 0)
220 // Set to Saturn if current object is not in the list.
221 m_CurrentObjectIndex = 13;
222 m_ObjectName = m_ObjectNames.at(m_CurrentObjectIndex);
223
224 QComboBox *objectSelector = new QComboBox(this);
225 objectSelector->addItems(m_ObjectNames);
226 objectSelector->setToolTip(i18n("This allows you to select a new object/target for XPlanet to view"));
227 selectorsLayout->addWidget(objectSelector);
228 objectSelector->setCurrentIndex(m_CurrentObjectIndex);
229 connect(objectSelector, SIGNAL(currentIndexChanged(int)), this, SLOT(updateXPlanetObject(int)));
230
231 m_CurrentOriginIndex = EARTH;
232 m_OriginName = m_ObjectNames.at(EARTH);
233
234 selectorsLayout->addWidget(new QLabel(i18n("from"), this));
235 m_OriginSelector = new QComboBox(this);
236 m_OriginSelector->addItems(m_ObjectNames);
237 m_OriginSelector->setToolTip(i18n("This allows you to select a viewing location"));
238 selectorsLayout->addWidget(m_OriginSelector);
239 m_OriginSelector->setCurrentIndex(EARTH);
240 connect(m_OriginSelector, SIGNAL(currentIndexChanged(int)), this, SLOT(updateXPlanetOrigin(int)));
241
242 m_lat = Options::xplanetLatitude().toDouble();
243 m_lon = Options::xplanetLongitude().toDouble();
244 m_Radius = 45;
245
246 selectorsLayout->addWidget(new QLabel(i18n("Location:"), this));
247
248 m_PositionDisplay = new QLabel(this);
249 m_PositionDisplay->setToolTip(i18n("XPlanet Latitude, Longitude, and object radius in %. This is only valid when viewing the object from the same object"));
250 updatePositionDisplay();
251 m_PositionDisplay->setDisabled(true);
252 selectorsLayout->addWidget(m_PositionDisplay);
253
254 QPushButton *resetXPlanetLocation = new QPushButton(this);
255 resetXPlanetLocation->setIcon(QIcon::fromTheme("system-reboot"));
256 resetXPlanetLocation->setAttribute(Qt::WA_LayoutUsesWidgetRect);
257 resetXPlanetLocation->setMaximumSize(QSize(32, 32));
258 resetXPlanetLocation->setMinimumSize(QSize(32, 32));
259 resetXPlanetLocation->setToolTip(i18n("Reset XPlanet Location to the location specified in the XPlanet Options"));
260 selectorsLayout->addWidget(resetXPlanetLocation);
261 connect(resetXPlanetLocation, SIGNAL(clicked()), this, SLOT(resetLocation()));
262
263 m_FreeRotate = new QPushButton(this);
264 m_FreeRotate->setIcon(QIcon::fromTheme("object-rotate-left"));
265 m_FreeRotate->setAttribute(Qt::WA_LayoutUsesWidgetRect);
266 m_FreeRotate->setMaximumSize(QSize(32, 32));
267 m_FreeRotate->setMinimumSize(QSize(32, 32));
268 m_FreeRotate->setCheckable(true);
269 m_FreeRotate->setToolTip(i18n("Hover over target and freely rotate view with mouse in XPlanet Viewer"));
270 selectorsLayout->addWidget(m_FreeRotate);
271 connect(m_FreeRotate, SIGNAL(clicked()), this, SLOT(slotFreeRotate()));
272
273 QPushButton *reCenterB = new QPushButton(this);
274 reCenterB->setIcon(QIcon::fromTheme("snap-bounding-box-center"));
276 reCenterB->setMaximumSize(QSize(32, 32));
277 reCenterB->setMinimumSize(QSize(32, 32));
278 reCenterB->setToolTip(i18n("Recenters the XPlanet image once it has been moved"));
279 selectorsLayout->addWidget(reCenterB);
280 connect(reCenterB, SIGNAL(clicked()), this, SLOT(reCenterXPlanet()));
281
282 QPushButton *saveB = new QPushButton(this);
283 saveB->setIcon(QIcon::fromTheme("document-save"));
285 saveB->setMaximumSize(QSize(32, 32));
286 saveB->setMinimumSize(QSize(32, 32));
287 saveB->setToolTip(i18n("Save the image to disk"));
288 selectorsLayout->addWidget(saveB);
289 connect(saveB, SIGNAL(clicked()), this, SLOT(saveFileToDisk()));
290
291 QWidget *viewControlsWidget = new QWidget(this);
292 QHBoxLayout *viewControlsLayout = new QHBoxLayout(viewControlsWidget);
293 viewControlsLayout->setContentsMargins(0, 0, 0, 0);
294 mainLayout->addWidget(viewControlsWidget);
295
296 viewControlsLayout->addWidget(new QLabel(i18n("FOV:"), this));
297
298 m_FOVEdit = new NonLinearDoubleSpinBox();
299 m_FOVEdit->setDecimals(5);
300 QList<double> possibleValues;
301 possibleValues << 0;
302 for(double i = .0001; i < 100; i *= 1.5)
303 possibleValues << i;
304 m_FOVEdit->setRecommendedValues(possibleValues);
305 m_FOVEdit->setToolTip(i18n("Sets the FOV to the Specified value. Note: has no effect if hovering over object."));
306 viewControlsLayout->addWidget(m_FOVEdit);
307
308 if (Options::xplanetFOV())
309 m_FOV = KStars::Instance()->map()->fov();
310 else
311 m_FOV = m_objectDefaultFOVs.at( m_CurrentObjectIndex);
312 m_FOVEdit->setValue(m_FOV);
313
314 connect(m_FOVEdit, SIGNAL(valueChanged(double)), this, SLOT(updateXPlanetFOVEdit()));
315
316 m_KStarsFOV = new QPushButton(this);
317 m_KStarsFOV->setIcon(QIcon::fromTheme("zoom-fit-width"));
318 m_KStarsFOV->setAttribute(Qt::WA_LayoutUsesWidgetRect);
319 m_KStarsFOV->setMaximumSize(QSize(32, 32));
320 m_KStarsFOV->setMinimumSize(QSize(32, 32));
321 m_KStarsFOV->setToolTip(i18n("Zoom to the current KStars FOV. Note: has no effect if hovering over object."));
322 viewControlsLayout->addWidget(m_KStarsFOV);
323 connect(m_KStarsFOV, SIGNAL(clicked()), this, SLOT(setKStarsXPlanetFOV()));
324
325 m_setFOV = new QPushButton(this);
326 m_setFOV->setIcon(QIcon::fromTheme("view-list-details"));
327 m_setFOV->setAttribute(Qt::WA_LayoutUsesWidgetRect);
328 m_setFOV->setMaximumSize(QSize(32, 32));
329 m_setFOV->setMinimumSize(QSize(32, 32));
330 m_setFOV->setToolTip(i18n("Zoom to a specific FOV. This has no effect when hovering over an object"));
331 viewControlsLayout->addWidget(m_setFOV);
332 connect(m_setFOV, SIGNAL(clicked()), this, SLOT(setFOVfromList()));
333
334 m_NoFOV = new QPushButton(this);
335 m_NoFOV->setIcon(QIcon::fromTheme("system-reboot"));
336 m_NoFOV->setAttribute(Qt::WA_LayoutUsesWidgetRect);
337 m_NoFOV->setMaximumSize(QSize(32, 32));
338 m_NoFOV->setMinimumSize(QSize(32, 32));
339 m_NoFOV->setToolTip(i18n("Optimum FOV for the target, FOV parameter not specified. Note: has no effect if hovering over object."));
340 viewControlsLayout->addWidget(m_NoFOV);
341 connect(m_NoFOV, SIGNAL(clicked()), this, SLOT(resetXPlanetFOV()));
342
343 m_Rotation = 0;
344
345 viewControlsLayout->addWidget(new QLabel(i18n("Rotation:"), this));
346
347 m_RotateEdit = new QSpinBox();
348
349 m_RotateEdit->setRange(-180, 180);
350 m_RotateEdit->setValue(0);
351 m_RotateEdit->setSingleStep(10);
352 m_RotateEdit->setToolTip(i18n("Set the view rotation to the desired angle"));
353 viewControlsLayout->addWidget(m_RotateEdit);
354 connect(m_RotateEdit, SIGNAL(valueChanged(int)), this, SLOT(updateXPlanetRotationEdit()));
355
356 QPushButton *invertRotation = new QPushButton(this);
357 invertRotation->setIcon(QIcon::fromTheme("object-flip-vertical"));
359 invertRotation->setMaximumSize(QSize(32, 32));
360 invertRotation->setMinimumSize(QSize(32, 32));
361 invertRotation->setToolTip(i18n("Rotate the view 180 degrees"));
362 viewControlsLayout->addWidget(invertRotation);
363 connect(invertRotation, SIGNAL(clicked()), this, SLOT(invertXPlanetRotation()));
364
365 QPushButton *resetRotation = new QPushButton(this);
366 resetRotation->setIcon(QIcon::fromTheme("system-reboot"));
368 resetRotation->setMaximumSize(QSize(32, 32));
369 resetRotation->setMinimumSize(QSize(32, 32));
370 resetRotation->setToolTip(i18n("Reset view rotation to 0"));
371 viewControlsLayout->addWidget(resetRotation);
372 connect(resetRotation, SIGNAL(clicked()), this, SLOT(resetXPlanetRotation()));
373
374 QPushButton *optionsB = new QPushButton(this);
375 optionsB->setIcon(QIcon::fromTheme("configure"));
377 optionsB->setMaximumSize(QSize(32, 32));
378 optionsB->setMinimumSize(QSize(32, 32));
379 optionsB->setToolTip(i18n("Bring up XPlanet Options"));
380 viewControlsLayout->addWidget(optionsB);
381 connect(optionsB, SIGNAL(clicked()), KStars::Instance(), SLOT(slotViewOps()));
382
383 QPushButton *invertB = new QPushButton(this);
384 invertB->setIcon(QIcon::fromTheme("edit-select-invert"));
386 invertB->setMaximumSize(QSize(32, 32));
387 invertB->setMinimumSize(QSize(32, 32));
388 invertB->setToolTip(i18n("Reverse colors of the image. This is useful to enhance contrast at times. This affects "
389 "only the display and not the saving."));
390 viewControlsLayout->addWidget(invertB);
391 connect(invertB, SIGNAL(clicked()), this, SLOT(invertColors()));
392
393 QWidget *timeWidget = new QWidget(this);
394 QHBoxLayout *timeLayout = new QHBoxLayout(timeWidget);
395 mainLayout->addWidget(timeWidget);
396 timeLayout->setContentsMargins(0, 0, 0, 0);
397
398 m_XPlanetTime = KStarsData::Instance()->lt();
399
400 QPushButton *setTime = new QPushButton(this);
401 setTime->setIcon(QIcon::fromTheme("clock"));
403 setTime->setMaximumSize(QSize(32, 32));
404 setTime->setMinimumSize(QSize(32, 32));
405 setTime->setToolTip(i18n("Allows you to set the XPlanet time to a different date/time from KStars"));
406 timeLayout->addWidget(setTime);
407 connect(setTime, SIGNAL(clicked()), this, SLOT(setXPlanetTime()));
408
409 QPushButton *kstarsTime = new QPushButton(this);
410 kstarsTime->setIcon(QIcon::fromTheme("system-reboot"));
412 kstarsTime->setMaximumSize(QSize(32, 32));
413 kstarsTime->setMinimumSize(QSize(32, 32));
414 kstarsTime->setToolTip(i18n("Sets the XPlanet time to the current KStars time"));
415 timeLayout->addWidget(kstarsTime);
416 connect(kstarsTime, SIGNAL(clicked()), this, SLOT(setXPlanetTimetoKStarsTime()));
417
418 m_XPlanetTimeDisplay = new QLabel(this);
419 m_XPlanetTimeDisplay->setToolTip(i18n("Current XPlanet Time"));
420 timeLayout->addWidget(m_XPlanetTimeDisplay);
421
422 m_XPlanetTimeDisplay->setText(i18n("%1, %2", m_XPlanetTime.date().toString(), m_XPlanetTime.time().toString()));
423
424 m_TimeSlider = new QSlider(Qt::Horizontal, this);
425 m_TimeSlider->setTracking(false);
426 connect(m_TimeSlider, SIGNAL(sliderMoved(int)), this, SLOT(timeSliderDisplay(int)));
427 timeLayout->addWidget(m_TimeSlider);
428 m_TimeSlider->setRange(-100, 100);
429 m_TimeSlider->setToolTip(i18n("This sets the time step from the current XPlanet time, good for viewing events"));
430 connect(m_TimeSlider, SIGNAL(valueChanged(int)), this, SLOT(updateXPlanetTime(int)));
431
432 m_TimeEdit = new QSpinBox(this);
433 m_TimeEdit->setRange(-10000, 10000);
434 m_TimeEdit->setMaximumWidth(50);
435 m_TimeEdit->setToolTip(i18n("This sets the time step from the current XPlanet time"));
436 timeLayout->addWidget(m_TimeEdit);
437 connect(m_TimeEdit, SIGNAL(valueChanged(int)), this, SLOT(updateXPlanetTimeEdit()));
438
439 m_CurrentTimeUnitIndex = MINS;
440 m_TimeUnitsSelect = new QComboBox(this);
441 timeLayout->addWidget(m_TimeUnitsSelect);
442 m_TimeUnitsSelect->addItem(i18n("years"));
443 m_TimeUnitsSelect->addItem(i18n("months"));
444 m_TimeUnitsSelect->addItem(i18n("days"));
445 m_TimeUnitsSelect->addItem(i18n("hours"));
446 m_TimeUnitsSelect->addItem(i18n("minutes"));
447 m_TimeUnitsSelect->addItem(i18n("seconds"));
448 m_TimeUnitsSelect->setCurrentIndex(MINS);
449 m_TimeUnitsSelect->setToolTip(i18n("Lets you change the units for the timestep in the animation"));
450 connect(m_TimeUnitsSelect, SIGNAL(currentIndexChanged(int)), this, SLOT(updateXPlanetTimeUnits(int)));
451
452 m_XPlanetTimer = new QTimer(this);
453 m_XPlanetTimer->setInterval(Options::xplanetAnimationDelay());
454 connect(m_XPlanetTimer, SIGNAL(timeout()), this, SLOT(incrementXPlanetTime()));
455
456 m_RunTime = new QPushButton(this);
457 m_RunTime->setIcon(QIcon::fromTheme("media-playback-start"));
458 m_RunTime->setAttribute(Qt::WA_LayoutUsesWidgetRect);
459 m_RunTime->setCheckable(true);
460 m_RunTime->setMaximumSize(QSize(32, 32));
461 m_RunTime->setMinimumSize(QSize(32, 32));
462 m_RunTime->setToolTip(i18n("Lets you run the animation"));
463 timeLayout->addWidget(m_RunTime);
464 connect(m_RunTime, SIGNAL(clicked()), this, SLOT(toggleXPlanetRun()));
465
466 QPushButton *resetTime = new QPushButton(this);
467 resetTime->setIcon(QIcon::fromTheme("system-reboot"));
469 resetTime->setMaximumSize(QSize(32, 32));
470 resetTime->setMinimumSize(QSize(32, 32));
471 resetTime->setToolTip(i18n("Resets the animation to 0 timesteps from the current XPlanet Time"));
472 timeLayout->addWidget(resetTime);
473 connect(resetTime, SIGNAL(clicked()), this, SLOT(resetXPlanetTime()));
474
475 m_View = new XPlanetImageLabel(page);
476 m_View->setAutoFillBackground(false);
477 m_Caption = new QLabel(page);
478 m_Caption->setAutoFillBackground(true);
479 m_Caption->setFrameShape(QFrame::StyledPanel);
480 m_Caption->setText(m_ObjectName);
481 // Add layout
482 QVBoxLayout *vlay = new QVBoxLayout(page);
483 vlay->setSpacing(0);
484 vlay->setContentsMargins(0, 0, 0, 0);
485 vlay->addWidget(m_View);
486 vlay->addWidget(m_Caption);
487
488
489 connect(m_View, SIGNAL(zoomIn()), this, SLOT(zoomInXPlanetFOV()));
490 connect(m_View, SIGNAL(zoomOut()), this, SLOT(zoomOutXPlanetFOV()));
491 connect(m_View, SIGNAL(changePosition(QPoint)), this, SLOT(changeXPlanetPosition(QPoint)));
492 connect(m_View, SIGNAL(changeLocation(QPoint)), this, SLOT(changeXPlanetLocation(QPoint)));
493
494 //Reverse colors
495 QPalette p = palette();
498 m_Caption->setPalette(p);
499 m_View->setPalette(p);
500
501#ifndef Q_OS_WIN
502 if(Options::xplanetUseFIFO())
503 {
504 connect(&watcherTimeout, SIGNAL(timeout()), &fifoImageLoadWatcher, SLOT(cancel()));
505 connect(&fifoImageLoadWatcher, SIGNAL(finished()), this, SLOT(showImage()));
506 }
507#endif
508
509
510#ifdef Q_OS_MACOS
512 for (auto &button : qButtons)
513 button->setAutoDefault(false);
514#endif
515 updateXPlanetTime(0);
516#endif
517}
518
523
524void XPlanetImageViewer::startXplanet()
525{
526 if(m_XPlanetRunning)
527 return;
528
529 //This means something failed in the file output
530 if(!setupOutputFile())
531 return;
532
533 QString xPlanetLocation = Options::xplanetPath();
534#ifdef Q_OS_MACOS
535 if (Options::xplanetIsInternal())
536 xPlanetLocation = QCoreApplication::applicationDirPath() + QDir::separator() + "xplanet";
537#endif
538
539 // If Options::xplanetPath() is empty, return
540 if (xPlanetLocation.isEmpty())
541 {
542 KSNotification::error(i18n("Xplanet binary path is empty in config panel."));
543 return;
544 }
545
546 // If Options::xplanetPath() does not exist, return
547 const QFileInfo xPlanetLocationInfo(xPlanetLocation);
548 if (!xPlanetLocationInfo.exists() || !xPlanetLocationInfo.isExecutable())
549 {
550 KSNotification::error(i18n("The configured Xplanet binary does not exist or is not executable."));
551 return;
552 }
553
554 // Create xplanet process
555 QProcess *xplanetProc = new QProcess(this);
556
557 // Add some options
558 QStringList args;
559
560 //This specifies the object to be viewed
561 args << "-body" << m_ObjectName.toLower();
562 //This is the date and time requested
563 args << "-date" << m_Date;
564 //This is the glare from the sun
565 args << "-glare" << Options::xplanetGlare();
566 args << "-base_magnitude" << Options::xplanetMagnitude();
567 //This is the correction for light's travel time.
568 args << "-light_time";
569
570 args << "-geometry" << QString::number(Options::xplanetWidth()) + 'x' + QString::number(Options::xplanetHeight());
571
572 if(m_FOV != 0)
573 args << "-fov" << QString::number(m_FOV);
574 //Need to convert to locale for places that don't use decimals??
575 //args << "-fov" << fov.setNum(fov());//.replace('.', ',');
576
577 //This rotates the view for different object angles
578 args << "-rotate" << QString::number(m_Rotation);
579
580 if (Options::xplanetConfigFile())
581 args << "-config" << Options::xplanetConfigFilePath();
582 if (Options::xplanetStarmap())
583 args << "-starmap" << Options::xplanetStarmapPath();
584 if (Options::xplanetArcFile())
585 args << "-arc_file" << Options::xplanetArcFilePath();
586 if (!m_File.fileName().isEmpty())
587 args << "-output" << m_File.fileName() << "-quality" << Options::xplanetQuality();
588
589 // Labels
590 if (Options::xplanetLabel())
591 {
592 args << "-fontsize" << Options::xplanetFontSize() << "-color"
593 << "0x" + Options::xplanetColor().mid(1) << "-date_format" << Options::xplanetDateFormat();
594
595 if (Options::xplanetLabelGMT())
596 args << "-gmtlabel";
597 else
598 args << "-label";
599 if (!Options::xplanetLabelString().isEmpty())
600 args << "-label_string"
601 << "\"" + Options::xplanetLabelString() + "\"";
602 if (Options::xplanetLabelTL())
603 args << "-labelpos"
604 << "+15+15";
605 else if (Options::xplanetLabelTR())
606 args << "-labelpos"
607 << "-15+15";
608 else if (Options::xplanetLabelBR())
609 args << "-labelpos"
610 << "-15-15";
611 else if (Options::xplanetLabelBL())
612 args << "-labelpos"
613 << "+15-15";
614 }
615
616 // Markers
617 if (Options::xplanetMarkerFile())
618 args << "-marker_file" << Options::xplanetMarkerFilePath();
619 if (Options::xplanetMarkerBounds())
620 args << "-markerbounds" << Options::xplanetMarkerBoundsPath();
621
622 // Position
623 // This sets the position from which the planet is viewed.
624 // Note that setting Latitude and Longitude means that position above the SAME object
625
626 if(m_CurrentObjectIndex == m_CurrentOriginIndex)
627 {
628 if (Options::xplanetRandom())
629 args << "-random";
630 else
631 args << "-latitude" << QString::number(m_lat) << "-longitude" << QString::number(m_lon) << "-radius" << QString::number(m_Radius);
632 }
633 else
634 args << "-origin" << m_OriginName;
635
636 //Centering
637 //This allows you to recenter the xplanet view
638
639 args << "-center" << "+" + QString::number(Options::xplanetWidth() / 2 + center.x()) + "+" + QString::number(Options::xplanetHeight() / 2 + center.y());
640
641 // Projection
642 if (Options::xplanetProjection())
643 {
644 switch (Options::xplanetProjection())
645 {
646 case 1:
647 args << "-projection"
648 << "ancient";
649 break;
650 case 2:
651 args << "-projection"
652 << "azimuthal";
653 break;
654 case 3:
655 args << "-projection"
656 << "bonne";
657 break;
658 case 4:
659 args << "-projection"
660 << "gnomonic";
661 break;
662 case 5:
663 args << "-projection"
664 << "hemisphere";
665 break;
666 case 6:
667 args << "-projection"
668 << "lambert";
669 break;
670 case 7:
671 args << "-projection"
672 << "mercator";
673 break;
674 case 8:
675 args << "-projection"
676 << "mollweide";
677 break;
678 case 9:
679 args << "-projection"
680 << "orthographic";
681 break;
682 case 10:
683 args << "-projection"
684 << "peters";
685 break;
686 case 11:
687 args << "-projection"
688 << "polyconic";
689 break;
690 case 12:
691 args << "-projection"
692 << "rectangular";
693 break;
694 case 13:
695 args << "-projection"
696 << "tsc";
697 break;
698 default:
699 break;
700 }
701 if (Options::xplanetBackground())
702 {
703 if (Options::xplanetBackgroundImage())
704 args << "-background" << Options::xplanetBackgroundImagePath();
705 else
706 args << "-background"
707 << "0x" + Options::xplanetBackgroundColorValue().mid(1);
708 }
709 }
710
711#ifdef Q_OS_MACOS
713 args << "-searchdir" << searchDir;
714#endif
715
716#ifdef Q_OS_WIN
717 QString searchDir = xPlanetLocationInfo.dir().absolutePath() + QDir::separator() + "xplanet";
718 args << "-searchdir" << searchDir;
719#endif
720
721 //This prevents it from running forever.
722 args << "-num_times" << "1";
723
724 m_XPlanetRunning = true;
725 m_ImageLoadSucceeded = false; //This will be set to true if it works.
726 uint32_t timeout = Options::xplanetTimeout();
727
728 //FIFO files don't work on windows
729#ifndef Q_OS_WIN
730 if(Options::xplanetUseFIFO())
731 {
732#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
733 fifoImageLoadWatcher.setFuture(QtConcurrent::run(&XPlanetImageViewer::loadImage, this));
734#else
735 fifoImageLoadWatcher.setFuture(QtConcurrent::run(this, &XPlanetImageViewer::loadImage));
736#endif
737 watcherTimeout.setSingleShot(true);
738 watcherTimeout.start(timeout);
739 }
740#endif
741
742 xplanetProc->start(xPlanetLocation, args);
743
744 //Uncomment to print the XPlanet commands to the console
745 // qDebug() << Q_FUNC_INFO << "Run:" << xplanetProc->program() << args.join(" ");
746
747 bool XPlanetSucceeded = xplanetProc->waitForFinished(timeout);
748 m_XPlanetRunning = false;
749 xplanetProc->kill(); //In case it timed out
750 xplanetProc->deleteLater();
751 if(XPlanetSucceeded)
752 {
753 if(m_FOV == 0)
754 m_Caption->setText(i18n("XPlanet View: %1 from %2 on %3", m_ObjectName, m_OriginName, m_DateText));
755 else
756 m_Caption->setText(i18n("XPlanet View: %1 from %2 on %3 at FOV: %4 deg", m_ObjectName, m_OriginName, m_DateText, m_FOV));
757#ifdef Q_OS_WIN
758 loadImage(); //This will also set imageLoadSucceeded based on whether it worked.
759#else
760 if(Options::xplanetUseFIFO())
761 return; //The loading of the image is handled with the watcher
762 else
763 loadImage(); //This will also set imageLoadSucceeded based on whether it worked.
764#endif
765
766 if(m_ImageLoadSucceeded)
767 showImage();
768 else
769 {
770 KSNotification::error(i18n("Loading of the image of object %1 failed.", m_ObjectName));
771 }
772 }
773 else
774 {
775 KStars::Instance()->statusBar()->showMessage(i18n("XPlanet failed to generate the image for object %1 before the timeout expired.", m_ObjectName));
776#ifndef Q_OS_WIN
777 if(Options::xplanetUseFIFO())
778 fifoImageLoadWatcher.cancel();
779#endif
780 }
781}
782
783bool XPlanetImageViewer::setupOutputFile()
784{
785#ifndef Q_OS_WIN
786 if(Options::xplanetUseFIFO())
787 {
788 if(m_File.fileName().contains("xplanetfifo") && m_File.exists())
789 return true;
790 QDir kstarsTempDir(KSPaths::writableLocation(QStandardPaths::TempLocation) + QDir::separator() + qAppName());
791 kstarsTempDir.mkpath(".");
792 m_File.setFileName(kstarsTempDir.filePath(QString("xplanetfifo%1.png").arg(QUuid::createUuid().toString().mid(1, 8)).toLatin1()));
793 if (mkfifo(m_File.fileName().toLatin1(), S_IRUSR | S_IWUSR) < 0)
794 {
795 KSNotification::error(i18n("Error making FIFO file %1: %2.", m_File.fileName(), strerror(errno)));
796 return false;
797 }
798 return true;
799 }
800#endif
801
802 //If the user is using windows or has not selected to use FIFO, it uses files in the KStars data directory.
803 QDir xPlanetDirPath(KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + QDir::separator() + "xplanet");
804 xPlanetDirPath.mkpath(".");
805 m_File.setFileName(xPlanetDirPath.filePath(m_ObjectName + ".png"));
806 return true;
807}
808
809void XPlanetImageViewer::zoomInXPlanetFOV()
810{
811 if(m_CurrentObjectIndex == m_CurrentOriginIndex)
812 {
813 m_Radius += 5;
814 updatePositionDisplay();
815 startXplanet();
816 }
817 else
818 {
819 m_FOVEdit->stepDown();
820 startXplanet();
821 }
822
823}
824
825void XPlanetImageViewer::zoomOutXPlanetFOV()
826{
827 if(m_CurrentObjectIndex == m_CurrentOriginIndex)
828 {
829 if(m_Radius > 0)
830 {
831 m_Radius -= 5;
832 updatePositionDisplay();
833 startXplanet();
834 }
835 }
836 else
837 {
838 m_FOVEdit->stepUp();
839 startXplanet();
840 }
841
842}
843
844void XPlanetImageViewer::updatePositionDisplay()
845{
846 m_PositionDisplay->setText(i18n("%1, %2, %3", QString::number(m_lat), QString::number(m_lon), QString::number(m_Radius)));
847}
848
849void XPlanetImageViewer::updateXPlanetTime(int timeShift)
850{
851
852 KStarsDateTime shiftedXPlanetTime;
853 switch(m_CurrentTimeUnitIndex)
854 {
855 case YEARS:
856 shiftedXPlanetTime = m_XPlanetTime.addDays(timeShift * 365);
857 break;
858
859 case MONTHS:
860 shiftedXPlanetTime = m_XPlanetTime.addDays(timeShift * 30);
861 break;
862
863 case DAYS:
864 shiftedXPlanetTime = m_XPlanetTime.addDays(timeShift);
865 break;
866
867 case HOURS:
868 shiftedXPlanetTime = m_XPlanetTime.addSecs(timeShift * 3600);
869 break;
870
871 case MINS:
872 shiftedXPlanetTime = m_XPlanetTime.addSecs(timeShift * 60);
873 break;
874
875 case SECS:
876 shiftedXPlanetTime = m_XPlanetTime.addSecs(timeShift);
877 break;
878 }
879
880 setXPlanetDate(shiftedXPlanetTime);
881 m_DateText = i18n("%1, %2", shiftedXPlanetTime.date().toString(), shiftedXPlanetTime.time().toString());
882 if(m_TimeEdit->value() != timeShift)
883 m_TimeEdit->setValue(timeShift);
884 else
885 startXplanet();
886}
887
888void XPlanetImageViewer::updateXPlanetObject(int objectIndex)
889{
890 center = QPoint(0, 0);
891 m_CurrentObjectIndex = objectIndex;
892 m_ObjectName = m_ObjectNames.at(objectIndex);
893
894 setWindowTitle(i18nc("@title:window", "XPlanet Solar System Simulator: %1", m_ObjectName));
895 if(m_FreeRotate->isChecked())
896 m_OriginSelector->setCurrentIndex(m_CurrentObjectIndex);
897 if(m_CurrentObjectIndex == m_CurrentOriginIndex)
898 startXplanet();
899 else
900 resetXPlanetFOV();
901}
902
903void XPlanetImageViewer::updateXPlanetOrigin(int originIndex)
904{
905 center = QPoint(0, 0);
906 m_CurrentOriginIndex = originIndex;
907 m_OriginName = m_ObjectNames.at(originIndex);
908 if(m_CurrentObjectIndex == m_CurrentOriginIndex)
909 m_FreeRotate->setChecked(true);
910 else
911 m_FreeRotate->setChecked(false);
912 updateStates();//This will update the disabled/enabled states
913 startXplanet();
914}
915
916void XPlanetImageViewer::changeXPlanetLocation(QPoint delta)
917{
918 if(m_CurrentObjectIndex == m_CurrentOriginIndex)
919 {
920 double newLon = m_lon + delta.x();
921 double newLat = m_lat + delta.y();
922
923 newLat = qBound(-90.0, newLat, 90.0);
924
925 m_lon = newLon;
926 m_lat = newLat;
927
928 updatePositionDisplay();
929 startXplanet();
930 }
931}
932
933void XPlanetImageViewer::changeXPlanetPosition(QPoint delta)
934{
935 center.setX(center.x() + delta.x());
936 center.setY(center.y() + delta.y());
937 startXplanet();
938}
939
940void XPlanetImageViewer::reCenterXPlanet()
941{
942 center = QPoint(0, 0);
943 startXplanet();
944}
945
946void XPlanetImageViewer::resetLocation()
947{
948 m_lat = Options::xplanetLatitude().toDouble();
949 m_lon = Options::xplanetLongitude().toDouble();
950 m_Radius = 45;
951 updatePositionDisplay();
952 startXplanet();
953}
954
955void XPlanetImageViewer::slotFreeRotate()
956{
957 if(m_FreeRotate->isChecked())
958 m_OriginSelector->setCurrentIndex(m_CurrentObjectIndex);
959 else
960 m_OriginSelector->setCurrentIndex(EARTH);
961}
962
963void XPlanetImageViewer::updateStates()
964{
965 if(m_FreeRotate->isChecked())
966 {
967 m_FOVEdit->setDisabled(true);
968 m_KStarsFOV->setDisabled(true);
969 m_NoFOV->setDisabled(true);
970
971 m_PositionDisplay->setDisabled(false);
972 }
973 else
974 {
975 m_FOVEdit->setDisabled(false);
976 m_KStarsFOV->setDisabled(false);
977 m_NoFOV->setDisabled(false);
978
979 m_PositionDisplay->setDisabled(true);
980 }
981}
982
983void XPlanetImageViewer::setXPlanetDate(KStarsDateTime time)
984{
985 //Note Xplanet uses UT time for everything but we want the labels to all be LT
986 KStarsDateTime utTime = KStarsData::Instance()->geo()->LTtoUT(time);
987 m_Date = utTime.toString(Qt::ISODate)
988 .replace("-", QString(""))
989 .replace("T", ".")
990 .replace(":", QString(""))
991 .replace("Z", QString(""));
992}
993
994void XPlanetImageViewer::updateXPlanetTimeUnits(int units)
995{
996 m_CurrentTimeUnitIndex = units;
997 updateXPlanetTimeEdit();
998}
999
1000void XPlanetImageViewer::updateXPlanetTimeEdit()
1001{
1002 if(m_TimeSlider->isSliderDown())
1003 return;
1004 int timeShift = m_TimeEdit->value();
1005 if(m_TimeSlider->value() != timeShift)
1006 {
1007
1008 if(timeShift > m_TimeSlider->maximum() + 100)
1009 m_TimeSlider->setMaximum(timeShift);
1010 if(timeShift < m_TimeSlider->minimum() - 100)
1011 m_TimeSlider->setMinimum(timeShift);
1012 m_TimeSlider->setValue(timeShift);
1013 }
1014 else
1015 updateXPlanetTime(timeShift);
1016}
1017
1018void XPlanetImageViewer::timeSliderDisplay(int timeShift)
1019{
1020 m_TimeEdit->setValue(timeShift);
1021}
1022
1023void XPlanetImageViewer::incrementXPlanetTime()
1024{
1025 if(!m_XPlanetRunning)
1026 {
1027 int timeShift = m_TimeEdit->value();
1028 if(m_TimeSlider->maximum() <= timeShift)
1029 m_TimeSlider->setMaximum(timeShift + 100);
1030 if(m_TimeEdit->maximum() <= timeShift)
1031 m_TimeEdit->setMaximum(timeShift + 100);
1032 m_TimeSlider->setValue(timeShift + 1);
1033 }
1034}
1035
1036void XPlanetImageViewer::setXPlanetTime()
1037{
1038 QPointer<TimeDialog> timedialog = new TimeDialog(m_XPlanetTime, KStarsData::Instance()->geo(), this);
1039 if (timedialog->exec() == QDialog::Accepted)
1040 {
1041 m_XPlanetTime = timedialog->selectedDateTime();
1042 m_XPlanetTimeDisplay->setText(i18n("%1, %2", m_XPlanetTime.date().toString(), m_XPlanetTime.time().toString()));
1043 int timeShift = 0;
1044 m_TimeSlider->setRange(-100, 100);
1045 if(m_TimeSlider->value() != timeShift)
1046 m_TimeSlider->setValue(timeShift);
1047 else
1048 updateXPlanetTime(timeShift);
1049 }
1050}
1051
1052void XPlanetImageViewer::setXPlanetTimetoKStarsTime()
1053{
1054 m_XPlanetTime = KStarsData::Instance()->lt();
1055 m_XPlanetTimeDisplay->setText(i18n("%1, %2", m_XPlanetTime.date().toString(), m_XPlanetTime.time().toString()));
1056 int timeShift = 0;
1057 m_TimeSlider->setRange(-100, 100);
1058 if(m_TimeSlider->value() != timeShift)
1059 m_TimeSlider->setValue(timeShift);
1060 else
1061 updateXPlanetTime(timeShift);
1062}
1063
1064void XPlanetImageViewer::resetXPlanetTime()
1065{
1066 int timeShift = 0;
1067 m_TimeSlider->setRange(-100, 100);
1068 if(m_TimeSlider->value() != timeShift)
1069 m_TimeSlider->setValue(timeShift);
1070 else
1071 updateXPlanetTime(timeShift);
1072}
1073
1074void XPlanetImageViewer::toggleXPlanetRun()
1075{
1076 if(m_XPlanetTimer->isActive())
1077 {
1078 m_XPlanetTimer->stop();
1079#ifndef Q_OS_WIN
1080 if(Options::xplanetUseFIFO())
1081 fifoImageLoadWatcher.cancel();
1082#endif
1083 }
1084 else
1085 {
1086 m_XPlanetTimer->setInterval(Options::xplanetAnimationDelay());
1087 m_XPlanetTimer->start();
1088 }
1089}
1090
1091void XPlanetImageViewer::updateXPlanetFOVEdit()
1092{
1093 m_FOV = m_FOVEdit->value();
1094 startXplanet();
1095}
1096
1097void XPlanetImageViewer::resetXPlanetFOV()
1098{
1099 m_FOV = m_objectDefaultFOVs.at(m_CurrentObjectIndex);
1100 m_FOVEdit->setValue(m_FOV);
1101 startXplanet();
1102}
1103
1104void XPlanetImageViewer::setKStarsXPlanetFOV()
1105{
1106 m_FOV = KStars::Instance()->map()->fov();
1107 m_FOVEdit->setValue(m_FOV);
1108 startXplanet();
1109}
1110void XPlanetImageViewer::setFOVfromList()
1111{
1112 if (!KStarsData::Instance()->getAvailableFOVs().isEmpty())
1113 {
1114 // Ask the user to choose from a list of available FOVs.
1115 QMap<QString, const FOV *> nameToFovMap;
1116 for (const FOV *f : KStarsData::Instance()->getAvailableFOVs())
1117 {
1118 nameToFovMap.insert(f->name(), f);
1119 }
1120 bool ok = false;
1121 const FOV *fov = nullptr;
1122 fov = nameToFovMap[QInputDialog::getItem(this, i18n("Choose a field-of-view"),
1123 i18n("FOV to render in XPlanet:"), nameToFovMap.keys(), 0,
1124 false, &ok)];
1125 if (ok)
1126 {
1127 m_FOV = fov->sizeX() / 60 ; //Converting from arcmin to degrees
1128 m_FOVEdit->setValue(m_FOV);
1129 startXplanet();
1130 }
1131 }
1132}
1133
1134void XPlanetImageViewer::updateXPlanetRotationEdit()
1135{
1136 m_Rotation = m_RotateEdit->value();
1137 startXplanet();
1138}
1139
1140void XPlanetImageViewer::resetXPlanetRotation()
1141{
1142 m_RotateEdit->setValue(0);
1143}
1144
1145void XPlanetImageViewer::invertXPlanetRotation()
1146{
1147 m_RotateEdit->setValue(180);
1148}
1149
1151{
1152#ifndef KSTARS_LITE
1153
1154 if (!m_Image.load(m_File.fileName()))
1155 {
1156 m_ImageLoadSucceeded = false;
1157 return false;
1158 }
1159 m_ImageLoadSucceeded = true;
1160 return true;
1161#else
1162 imageLoadSucceeded = false;
1163 return false;
1164#endif
1165}
1166
1167bool XPlanetImageViewer::showImage()
1168{
1169#ifndef KSTARS_LITE
1170
1171 //If the image is larger than screen width and/or screen height,
1172 //shrink it to fit the screen
1173 QRect deskRect = QGuiApplication::primaryScreen()->geometry();
1174 int w = deskRect.width(); // screen width
1175 int h = deskRect.height(); // screen height
1176
1177 if (m_Image.width() <= w && m_Image.height() > h) //Window is taller than desktop
1178 m_Image = m_Image.scaled(int(m_Image.width() * h / m_Image.height()), h);
1179 else if (m_Image.height() <= h && m_Image.width() > w) //window is wider than desktop
1180 m_Image = m_Image.scaled(w, int(m_Image.height() * w / m_Image.width()));
1181 else if (m_Image.width() > w && m_Image.height() > h) //window is too tall and too wide
1182 {
1183 //which needs to be shrunk least, width or height?
1184 float fx = float(w) / float(m_Image.width());
1185 float fy = float(h) / float(m_Image.height());
1186 if (fx > fy) //width needs to be shrunk less, so shrink to fit in height
1187 m_Image = m_Image.scaled(int(m_Image.width() * fy), h);
1188 else //vice versa
1189 m_Image = m_Image.scaled(w, int(m_Image.height() * fx));
1190 }
1191 const bool initialLoad = !isVisible();
1192
1193 show(); // hide is default
1194
1195 m_View->setImage(m_Image);
1196 w = m_Image.width();
1197
1198 //If the caption is wider than the image, set the window size
1199 //to fit the caption
1200 if (m_Caption->width() > w)
1201 w = m_Caption->width();
1202 if(initialLoad)
1203 resize(w, m_Image.height());
1204 else
1205 {
1206 m_View->refreshImage();
1207 }
1208
1209 update();
1210 show();
1211
1212 return true;
1213#else
1214 return false;
1215#endif
1216}
1217
1218void XPlanetImageViewer::saveFileToDisk()
1219{
1220#ifndef KSTARS_LITE
1221 QFileDialog saveDialog(KStars::Instance(), i18nc("@title:window", "Save Image"), m_LastFile);
1222 saveDialog.setDefaultSuffix("png");
1223 saveDialog.setAcceptMode(QFileDialog::AcceptSave);
1224 saveDialog.exec();
1225
1226 if(saveDialog.result() == QFileDialog::Rejected)
1227 return;
1228 if(saveDialog.selectedFiles().isEmpty())
1229 return;
1230 QString newFileName = saveDialog.selectedFiles().first();
1231 if(newFileName.isEmpty())
1232 return;
1233
1234 m_LastFile = newFileName;
1235
1236 saveFile(newFileName);
1237
1238#endif
1239}
1240
1241void XPlanetImageViewer::saveFile(const QString &fileName)
1242{
1243#ifndef KSTARS_LITE
1244
1245 if (! m_Image.save(fileName, "png"))
1246 {
1247 KSNotification::error(i18n("Saving of the image to %1 failed.", fileName));
1248 }
1249 else
1250 KStars::Instance()->statusBar()->showMessage(i18n("Saved image to %1", fileName));
1251#endif
1252}
1253
1254void XPlanetImageViewer::invertColors()
1255{
1256#ifndef KSTARS_LITE
1257 // Invert colors
1258 m_View->invertPixels();
1259 m_View->update();
1260#endif
1261}
1262
const KStarsDateTime & lt() const
Definition kstarsdata.h:153
GeoLocation * geo()
Definition kstarsdata.h:238
Extension of QDateTime for KStars KStarsDateTime can represent the date/time as a Julian Day,...
KStarsDateTime addDays(int nd) const
Modify the Date/Time by adding a number of days.
KStarsDateTime addSecs(double s) const
SkyMap * map() const
Definition kstars.h:139
static KStars * Instance()
Definition kstars.h:121
float fov()
Definition skymap.cpp:1204
XPlanet Image viewer QFrame for the KPlanetImageViewer for KStars.
XPlanetImageViewer(const QString &obj, QWidget *parent=nullptr)
Create xplanet image viewer from Object.
~XPlanetImageViewer() override
Destructor.
bool loadImage()
loadImage Load image and display it
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
char * toString(const EngineQuery &query)
GeoCoordinates geo(const QVariant &location)
void setIcon(const QIcon &icon)
void addWidget(QWidget *widget, int stretch, Qt::Alignment alignment)
virtual void setSpacing(int spacing) override
void addItems(const QStringList &texts)
void setCurrentIndex(int index)
QString applicationDirPath()
QString toString(QStringView format, QCalendar cal) const const
QDate date() const const
QTime time() const const
QString toString(QStringView format, QCalendar cal) const const
QDialog(QWidget *parent, Qt::WindowFlags f)
void finished(int result)
void setModal(bool modal)
QString homePath()
QChar separator()
void accept()
virtual bool event(QEvent *e) override
void restoreOverrideCursor()
QIcon fromTheme(const QString &name)
int height() const const
QImage scaled(const QSize &size, Qt::AspectRatioMode aspectRatioMode, Qt::TransformationMode transformMode) const const
int width() const const
QString getItem(QWidget *parent, const QString &title, const QString &label, const QStringList &items, int current, bool editable, bool *ok, Qt::WindowFlags flags, Qt::InputMethodHints inputMethodHints)
void setContentsMargins(const QMargins &margins)
QList< T > mid(qsizetype pos, qsizetype length) const const
QStatusBar * statusBar() const const
iterator insert(const Key &key, const T &value)
QList< Key > keys() const const
QPoint globalPos() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
void deleteLater()
QList< T > findChildren(Qt::FindChildOptions options) const const
QObject * parent() const const
bool begin(QPaintDevice *device)
void drawPixmap(const QPoint &point, const QPixmap &pixmap)
bool end()
void setColor(ColorGroup group, ColorRole role, const QColor &color)
QPixmap fromImage(QImage &&image, Qt::ImageConversionFlags flags)
int x() const const
int y() const const
void kill()
void start(OpenMode mode)
bool waitForFinished(int msecs)
int height() const const
int width() const const
Qt::MouseButtons buttons() const const
QString locate(StandardLocation type, const QString &fileName, LocateOptions options)
void showMessage(const QString &message, int timeout)
bool isEmpty() const const
QString number(double n, char format, int precision)
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
KeepAspectRatio
PinchGesture
RightButton
MouseEventSynthesizedBySystem
Horizontal
SmoothTransformation
WA_DeleteOnClose
QFuture< T > run(Function function,...)
QString toString(QStringView format) const const
QUuid createUuid()
Qt::MouseEventSource source() const const
QPoint angleDelta() const const
QWidget(QWidget *parent, Qt::WindowFlags f)
void setMaximumSize(const QSize &)
void setMinimumSize(const QSize &)
void setAttribute(Qt::WidgetAttribute attribute, bool on)
void setLayout(QLayout *layout)
void show()
void setToolTip(const QString &)
void update()
bool isVisible() const const
virtual void wheelEvent(QWheelEvent *event)
void setWindowFlags(Qt::WindowFlags type)
void setWindowTitle(const QString &)
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri Jan 24 2025 11:53:00 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.