Kstars

xplanetimageviewer.cpp
1 /*
2  SPDX-FileCopyrightText: Thomas Kabelmann
3  SPDX-FileCopyrightText: 2018 Robert Lancaster <[email protected]>
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 
41 typedef 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 
52 XPlanetImageLabel::XPlanetImageLabel(QWidget *parent) : QFrame(parent)
53 {
54 #ifndef KSTARS_LITE
57  setFrameStyle(QFrame::StyledPanel | QFrame::Plain);
58  setLineWidth(2);
59 #endif
60 }
61 
62 void 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 
70 void XPlanetImageLabel::invertPixels()
71 {
72 #ifndef KSTARS_LITE
73  m_Image.invertPixels();
75 #endif
76 }
77 
78 void 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 
91 void XPlanetImageLabel::resizeEvent(QResizeEvent *event)
92 {
93  if (event->size() == m_Pix.size())
94  return;
95 
97 }
98 
99 void XPlanetImageLabel::refreshImage()
100 {
102  update();
103 }
104 
105 void 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 
123 bool 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 
130 bool 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 
138 void XPlanetImageLabel::pinchTriggered(QPinchGesture *gesture)
139 {
140  if (gesture->totalScaleFactor() > 1)
141  emit zoomIn();
142  else
143  emit zoomOut();
144 }
145 
146 
147 void XPlanetImageLabel::mousePressEvent(QMouseEvent *e)
148 {
149  m_MouseButtonDown = true;
150  m_LastMousePoint = e->globalPos();
151  e->accept();
152 }
153 
154 void XPlanetImageLabel::mouseReleaseEvent(QMouseEvent *e)
155 {
156  m_MouseButtonDown = false;
157  e->accept();
158 }
159 
160 void 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_OSX
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"));
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"));
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"));
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"));
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"));
358  invertRotation->setAttribute(Qt::WA_LayoutUsesWidgetRect);
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"));
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);
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_OSX
511  QList<QPushButton *> qButtons = findChildren<QPushButton *>();
512  for (auto &button : qButtons)
513  button->setAutoDefault(false);
514 #endif
515  updateXPlanetTime(0);
516 #endif
517 }
518 
520 {
522 }
523 
524 void 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_OSX
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_OSX
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  fifoImageLoadWatcher.setFuture(QtConcurrent::run(this, &XPlanetImageViewer::loadImage));
733  watcherTimeout.setSingleShot(true);
734  watcherTimeout.start(timeout);
735  }
736 #endif
737 
738  xplanetProc->start(xPlanetLocation, args);
739 
740  //Uncomment to print the XPlanet commands to the console
741  // qDebug() << Q_FUNC_INFO << "Run:" << xplanetProc->program() << args.join(" ");
742 
743  bool XPlanetSucceeded = xplanetProc->waitForFinished(timeout);
744  m_XPlanetRunning = false;
745  xplanetProc->kill(); //In case it timed out
746  xplanetProc->deleteLater();
747  if(XPlanetSucceeded)
748  {
749  if(m_FOV == 0)
750  m_Caption->setText(i18n("XPlanet View: %1 from %2 on %3", m_ObjectName, m_OriginName, m_DateText));
751  else
752  m_Caption->setText(i18n("XPlanet View: %1 from %2 on %3 at FOV: %4 deg", m_ObjectName, m_OriginName, m_DateText, m_FOV));
753 #ifdef Q_OS_WIN
754  loadImage(); //This will also set imageLoadSucceeded based on whether it worked.
755 #else
756  if(Options::xplanetUseFIFO())
757  return; //The loading of the image is handled with the watcher
758  else
759  loadImage(); //This will also set imageLoadSucceeded based on whether it worked.
760 #endif
761 
762  if(m_ImageLoadSucceeded)
763  showImage();
764  else
765  {
766  KSNotification::error(i18n("Loading of the image of object %1 failed.", m_ObjectName));
767  }
768  }
769  else
770  {
771  KStars::Instance()->statusBar()->showMessage(i18n("XPlanet failed to generate the image for object %1 before the timeout expired.", m_ObjectName));
772 #ifndef Q_OS_WIN
773  if(Options::xplanetUseFIFO())
774  fifoImageLoadWatcher.cancel();
775 #endif
776  }
777 }
778 
779 bool XPlanetImageViewer::setupOutputFile()
780 {
781 #ifndef Q_OS_WIN
782  if(Options::xplanetUseFIFO())
783  {
784  if(m_File.fileName().contains("xplanetfifo") && m_File.exists())
785  return true;
786  QDir kstarsTempDir(KSPaths::writableLocation(QStandardPaths::TempLocation) + "/" + qAppName());
787  kstarsTempDir.mkpath(".");
788  m_File.setFileName(kstarsTempDir.filePath(QString("xplanetfifo%1.png").arg(QUuid::createUuid().toString().mid(1, 8)).toLatin1()));
789  int mkFifoSuccess = 0; //Note if the return value of the command is 0 it succeeded, -1 means it failed.
790  if ((mkFifoSuccess = mkfifo(m_File.fileName().toLatin1(), S_IRUSR | S_IWUSR) < 0))
791  {
792  KSNotification::error(i18n("Error making FIFO file %1: %2.", m_File.fileName(), strerror(errno)));
793  return false;
794  }
795  return true;
796  }
797 #endif
798 
799  //If the user is using windows or has not selected to use FIFO, it uses files in the KStars data directory.
800  QDir xPlanetDirPath(KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + "/" + "xplanet");
801  xPlanetDirPath.mkpath(".");
802  m_File.setFileName(xPlanetDirPath.filePath(m_ObjectName + ".png"));
803  return true;
804 }
805 
806 void XPlanetImageViewer::zoomInXPlanetFOV()
807 {
808  if(m_CurrentObjectIndex == m_CurrentOriginIndex)
809  {
810  m_Radius += 5;
811  updatePositionDisplay();
812  startXplanet();
813  }
814  else
815  {
816  m_FOVEdit->stepDown();
817  startXplanet();
818  }
819 
820 }
821 
822 void XPlanetImageViewer::zoomOutXPlanetFOV()
823 {
824  if(m_CurrentObjectIndex == m_CurrentOriginIndex)
825  {
826  if(m_Radius > 0)
827  {
828  m_Radius -= 5;
829  updatePositionDisplay();
830  startXplanet();
831  }
832  }
833  else
834  {
835  m_FOVEdit->stepUp();
836  startXplanet();
837  }
838 
839 }
840 
841 void XPlanetImageViewer::updatePositionDisplay()
842 {
843  m_PositionDisplay->setText(i18n("%1, %2, %3", QString::number(m_lat), QString::number(m_lon), QString::number(m_Radius)));
844 }
845 
846 void XPlanetImageViewer::updateXPlanetTime(int timeShift)
847 {
848 
849  KStarsDateTime shiftedXPlanetTime;
850  switch(m_CurrentTimeUnitIndex)
851  {
852  case YEARS:
853  shiftedXPlanetTime = m_XPlanetTime.addDays(timeShift * 365);
854  break;
855 
856  case MONTHS:
857  shiftedXPlanetTime = m_XPlanetTime.addDays(timeShift * 30);
858  break;
859 
860  case DAYS:
861  shiftedXPlanetTime = m_XPlanetTime.addDays(timeShift);
862  break;
863 
864  case HOURS:
865  shiftedXPlanetTime = m_XPlanetTime.addSecs(timeShift * 3600);
866  break;
867 
868  case MINS:
869  shiftedXPlanetTime = m_XPlanetTime.addSecs(timeShift * 60);
870  break;
871 
872  case SECS:
873  shiftedXPlanetTime = m_XPlanetTime.addSecs(timeShift);
874  break;
875  }
876 
877  setXPlanetDate(shiftedXPlanetTime);
878  m_DateText = i18n("%1, %2", shiftedXPlanetTime.date().toString(), shiftedXPlanetTime.time().toString());
879  if(m_TimeEdit->value() != timeShift)
880  m_TimeEdit->setValue(timeShift);
881  else
882  startXplanet();
883 }
884 
885 void XPlanetImageViewer::updateXPlanetObject(int objectIndex)
886 {
887  center = QPoint(0, 0);
888  m_CurrentObjectIndex = objectIndex;
889  m_ObjectName = m_ObjectNames.at(objectIndex);
890 
891  setWindowTitle(i18nc("@title:window", "XPlanet Solar System Simulator: %1", m_ObjectName));
892  if(m_FreeRotate->isChecked())
893  m_OriginSelector->setCurrentIndex(m_CurrentObjectIndex);
894  if(m_CurrentObjectIndex == m_CurrentOriginIndex)
895  startXplanet();
896  else
897  resetXPlanetFOV();
898 }
899 
900 void XPlanetImageViewer::updateXPlanetOrigin(int originIndex)
901 {
902  center = QPoint(0, 0);
903  m_CurrentOriginIndex = originIndex;
904  m_OriginName = m_ObjectNames.at(originIndex);
905  if(m_CurrentObjectIndex == m_CurrentOriginIndex)
906  m_FreeRotate->setChecked(true);
907  else
908  m_FreeRotate->setChecked(false);
909  updateStates();//This will update the disabled/enabled states
910  startXplanet();
911 }
912 
913 void XPlanetImageViewer::changeXPlanetLocation(QPoint delta)
914 {
915  if(m_CurrentObjectIndex == m_CurrentOriginIndex)
916  {
917  double newLon = m_lon + delta.x();
918  double newLat = m_lat + delta.y();
919 
920  newLat = qBound(-90.0, newLat, 90.0);
921 
922  m_lon = newLon;
923  m_lat = newLat;
924 
925  updatePositionDisplay();
926  startXplanet();
927  }
928 }
929 
930 void XPlanetImageViewer::changeXPlanetPosition(QPoint delta)
931 {
932  center.setX(center.x() + delta.x());
933  center.setY(center.y() + delta.y());
934  startXplanet();
935 }
936 
937 void XPlanetImageViewer::reCenterXPlanet()
938 {
939  center = QPoint(0, 0);
940  startXplanet();
941 }
942 
943 void XPlanetImageViewer::resetLocation()
944 {
945  m_lat = Options::xplanetLatitude().toDouble();
946  m_lon = Options::xplanetLongitude().toDouble();
947  m_Radius = 45;
948  updatePositionDisplay();
949  startXplanet();
950 }
951 
952 void XPlanetImageViewer::slotFreeRotate()
953 {
954  if(m_FreeRotate->isChecked())
955  m_OriginSelector->setCurrentIndex(m_CurrentObjectIndex);
956  else
957  m_OriginSelector->setCurrentIndex(EARTH);
958 }
959 
960 void XPlanetImageViewer::updateStates()
961 {
962  if(m_FreeRotate->isChecked())
963  {
964  m_FOVEdit->setDisabled(true);
965  m_KStarsFOV->setDisabled(true);
966  m_NoFOV->setDisabled(true);
967 
968  m_PositionDisplay->setDisabled(false);
969  }
970  else
971  {
972  m_FOVEdit->setDisabled(false);
973  m_KStarsFOV->setDisabled(false);
974  m_NoFOV->setDisabled(false);
975 
976  m_PositionDisplay->setDisabled(true);
977  }
978 }
979 
980 void XPlanetImageViewer::setXPlanetDate(KStarsDateTime time)
981 {
982  //Note Xplanet uses UT time for everything but we want the labels to all be LT
983  KStarsDateTime utTime = KStarsData::Instance()->geo()->LTtoUT(time);
984  m_Date = utTime.toString(Qt::ISODate)
985  .replace("-", QString(""))
986  .replace("T", ".")
987  .replace(":", QString(""))
988  .replace("Z", QString(""));
989 }
990 
991 void XPlanetImageViewer::updateXPlanetTimeUnits(int units)
992 {
993  m_CurrentTimeUnitIndex = units;
994  updateXPlanetTimeEdit();
995 }
996 
997 void XPlanetImageViewer::updateXPlanetTimeEdit()
998 {
999  if(m_TimeSlider->isSliderDown())
1000  return;
1001  int timeShift = m_TimeEdit->value();
1002  if(m_TimeSlider->value() != timeShift)
1003  {
1004 
1005  if(timeShift > m_TimeSlider->maximum() + 100)
1006  m_TimeSlider->setMaximum(timeShift);
1007  if(timeShift < m_TimeSlider->minimum() - 100)
1008  m_TimeSlider->setMinimum(timeShift);
1009  m_TimeSlider->setValue(timeShift);
1010  }
1011  else
1012  updateXPlanetTime(timeShift);
1013 }
1014 
1015 void XPlanetImageViewer::timeSliderDisplay(int timeShift)
1016 {
1017  m_TimeEdit->setValue(timeShift);
1018 }
1019 
1020 void XPlanetImageViewer::incrementXPlanetTime()
1021 {
1022  if(!m_XPlanetRunning)
1023  {
1024  int timeShift = m_TimeEdit->value();
1025  if(m_TimeSlider->maximum() <= timeShift)
1026  m_TimeSlider->setMaximum(timeShift + 100);
1027  if(m_TimeEdit->maximum() <= timeShift)
1028  m_TimeEdit->setMaximum(timeShift + 100);
1029  m_TimeSlider->setValue(timeShift + 1);
1030  }
1031 }
1032 
1033 void XPlanetImageViewer::setXPlanetTime()
1034 {
1035  QPointer<TimeDialog> timedialog = new TimeDialog(m_XPlanetTime, KStarsData::Instance()->geo(), this);
1036  if (timedialog->exec() == QDialog::Accepted)
1037  {
1038  m_XPlanetTime = timedialog->selectedDateTime();
1039  m_XPlanetTimeDisplay->setText(i18n("%1, %2", m_XPlanetTime.date().toString(), m_XPlanetTime.time().toString()));
1040  int timeShift = 0;
1041  m_TimeSlider->setRange(-100, 100);
1042  if(m_TimeSlider->value() != timeShift)
1043  m_TimeSlider->setValue(timeShift);
1044  else
1045  updateXPlanetTime(timeShift);
1046  }
1047 }
1048 
1049 void XPlanetImageViewer::setXPlanetTimetoKStarsTime()
1050 {
1051  m_XPlanetTime = KStarsData::Instance()->lt();
1052  m_XPlanetTimeDisplay->setText(i18n("%1, %2", m_XPlanetTime.date().toString(), m_XPlanetTime.time().toString()));
1053  int timeShift = 0;
1054  m_TimeSlider->setRange(-100, 100);
1055  if(m_TimeSlider->value() != timeShift)
1056  m_TimeSlider->setValue(timeShift);
1057  else
1058  updateXPlanetTime(timeShift);
1059 }
1060 
1061 void XPlanetImageViewer::resetXPlanetTime()
1062 {
1063  int timeShift = 0;
1064  m_TimeSlider->setRange(-100, 100);
1065  if(m_TimeSlider->value() != timeShift)
1066  m_TimeSlider->setValue(timeShift);
1067  else
1068  updateXPlanetTime(timeShift);
1069 }
1070 
1071 void XPlanetImageViewer::toggleXPlanetRun()
1072 {
1073  if(m_XPlanetTimer->isActive())
1074  {
1075  m_XPlanetTimer->stop();
1076 #ifndef Q_OS_WIN
1077  if(Options::xplanetUseFIFO())
1078  fifoImageLoadWatcher.cancel();
1079 #endif
1080  }
1081  else
1082  {
1083  m_XPlanetTimer->setInterval(Options::xplanetAnimationDelay());
1084  m_XPlanetTimer->start();
1085  }
1086 }
1087 
1088 void XPlanetImageViewer::updateXPlanetFOVEdit()
1089 {
1090  m_FOV = m_FOVEdit->value();
1091  startXplanet();
1092 }
1093 
1094 void XPlanetImageViewer::resetXPlanetFOV()
1095 {
1096  m_FOV = m_objectDefaultFOVs.at(m_CurrentObjectIndex);
1097  m_FOVEdit->setValue(m_FOV);
1098  startXplanet();
1099 }
1100 
1101 void XPlanetImageViewer::setKStarsXPlanetFOV()
1102 {
1103  m_FOV = KStars::Instance()->map()->fov();
1104  m_FOVEdit->setValue(m_FOV);
1105  startXplanet();
1106 }
1107 void XPlanetImageViewer::setFOVfromList()
1108 {
1109  if (!KStarsData::Instance()->getAvailableFOVs().isEmpty())
1110  {
1111  // Ask the user to choose from a list of available FOVs.
1112  QMap<QString, const FOV *> nameToFovMap;
1113  for (const FOV *f : KStarsData::Instance()->getAvailableFOVs())
1114  {
1115  nameToFovMap.insert(f->name(), f);
1116  }
1117  bool ok = false;
1118  const FOV *fov = nullptr;
1119  fov = nameToFovMap[QInputDialog::getItem(this, i18n("Choose a field-of-view"),
1120  i18n("FOV to render in XPlanet:"), nameToFovMap.keys(), 0,
1121  false, &ok)];
1122  if (ok)
1123  {
1124  m_FOV = fov->sizeX() / 60 ; //Converting from arcmin to degrees
1125  m_FOVEdit->setValue(m_FOV);
1126  startXplanet();
1127  }
1128  }
1129 }
1130 
1131 void XPlanetImageViewer::updateXPlanetRotationEdit()
1132 {
1133  m_Rotation = m_RotateEdit->value();
1134  startXplanet();
1135 }
1136 
1137 void XPlanetImageViewer::resetXPlanetRotation()
1138 {
1139  m_RotateEdit->setValue(0);
1140 }
1141 
1142 void XPlanetImageViewer::invertXPlanetRotation()
1143 {
1144  m_RotateEdit->setValue(180);
1145 }
1146 
1148 {
1149 #ifndef KSTARS_LITE
1150 
1151  if (!m_Image.load(m_File.fileName()))
1152  {
1153  m_ImageLoadSucceeded = false;
1154  return false;
1155  }
1156  m_ImageLoadSucceeded = true;
1157  return true;
1158 #else
1159  imageLoadSucceeded = false;
1160  return false;
1161 #endif
1162 }
1163 
1164 bool XPlanetImageViewer::showImage()
1165 {
1166 #ifndef KSTARS_LITE
1167 
1168  //If the image is larger than screen width and/or screen height,
1169  //shrink it to fit the screen
1170  QRect deskRect = QGuiApplication::primaryScreen()->geometry();
1171  int w = deskRect.width(); // screen width
1172  int h = deskRect.height(); // screen height
1173 
1174  if (m_Image.width() <= w && m_Image.height() > h) //Window is taller than desktop
1175  m_Image = m_Image.scaled(int(m_Image.width() * h / m_Image.height()), h);
1176  else if (m_Image.height() <= h && m_Image.width() > w) //window is wider than desktop
1177  m_Image = m_Image.scaled(w, int(m_Image.height() * w / m_Image.width()));
1178  else if (m_Image.width() > w && m_Image.height() > h) //window is too tall and too wide
1179  {
1180  //which needs to be shrunk least, width or height?
1181  float fx = float(w) / float(m_Image.width());
1182  float fy = float(h) / float(m_Image.height());
1183  if (fx > fy) //width needs to be shrunk less, so shrink to fit in height
1184  m_Image = m_Image.scaled(int(m_Image.width() * fy), h);
1185  else //vice versa
1186  m_Image = m_Image.scaled(w, int(m_Image.height() * fx));
1187  }
1188  const bool initialLoad = !isVisible();
1189 
1190  show(); // hide is default
1191 
1192  m_View->setImage(m_Image);
1193  w = m_Image.width();
1194 
1195  //If the caption is wider than the image, set the window size
1196  //to fit the caption
1197  if (m_Caption->width() > w)
1198  w = m_Caption->width();
1199  if(initialLoad)
1200  resize(w, m_Image.height());
1201  else
1202  {
1203  m_View->refreshImage();
1204  }
1205 
1206  update();
1207  show();
1208 
1209  return true;
1210 #else
1211  return false;
1212 #endif
1213 }
1214 
1215 void XPlanetImageViewer::saveFileToDisk()
1216 {
1217 #ifndef KSTARS_LITE
1218  QFileDialog saveDialog(KStars::Instance(), i18nc("@title:window", "Save Image"), m_LastFile);
1219  saveDialog.setDefaultSuffix("png");
1220  saveDialog.setAcceptMode(QFileDialog::AcceptSave);
1221  saveDialog.exec();
1222 
1223  if(saveDialog.result() == QFileDialog::Rejected)
1224  return;
1225  if(saveDialog.selectedFiles().isEmpty())
1226  return;
1227  QString newFileName = saveDialog.selectedFiles().first();
1228  if(newFileName.isEmpty())
1229  return;
1230 
1231  m_LastFile = newFileName;
1232 
1233  saveFile(newFileName);
1234 
1235 #endif
1236 }
1237 
1238 void XPlanetImageViewer::saveFile(const QString &fileName)
1239 {
1240 #ifndef KSTARS_LITE
1241 
1242  if (! m_Image.save(fileName, "png"))
1243  {
1244  KSNotification::error(i18n("Saving of the image to %1 failed.", fileName));
1245  }
1246  else
1247  KStars::Instance()->statusBar()->showMessage(i18n("Saved image to %1", fileName));
1248 #endif
1249 }
1250 
1251 void XPlanetImageViewer::invertColors()
1252 {
1253 #ifndef KSTARS_LITE
1254  // Invert colors
1255  m_View->invertPixels();
1256  m_View->update();
1257 #endif
1258 }
1259 
void start(const QString &program, const QStringList &arguments, QIODevice::OpenMode mode)
Definition: fov.h:27
Extension of QDateTime for KStars KStarsDateTime can represent the date/time as a Julian Day,...
void setMinimum(int)
QFuture< T > run(Function function,...)
bool isActive() const const
QPixmap fromImage(const QImage &image, Qt::ImageConversionFlags flags)
KStarsDateTime addDays(int nd) const
Modify the Date/Time by adding a number of days.
void setCheckable(bool)
void setText(const QString &)
QWidget(QWidget *parent, Qt::WindowFlags f)
QString number(int n, int base)
int height() const const
void drawPixmap(const QRectF &target, const QPixmap &pixmap, const QRectF &source)
const KStarsDateTime & lt() const
Definition: kstarsdata.h:150
virtual bool event(QEvent *e) override
bool waitForFinished(int msecs)
void setSizePolicy(QSizePolicy)
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)
QSize size() const const
void setDisabled(bool disable)
~XPlanetImageViewer() override
Destructor.
void setSingleShot(bool singleShot)
QChar separator()
void update()
QTime time() const const
QPoint angleDelta() const const
QIcon fromTheme(const QString &name)
bool isSliderDown() const const
int width() const const
QImage scaled(int width, int height, Qt::AspectRatioMode aspectRatioMode, Qt::TransformationMode transformMode) const const
void setCurrentIndex(int index)
SkyMap * map() const
Definition: kstars.h:143
QString applicationDirPath()
QByteArray toLatin1() const const
int x() const const
int y() const const
QString homePath()
bool isChecked() const const
void setAttribute(Qt::WidgetAttribute attribute, bool on)
void setFrameShape(QFrame::Shape)
RightButton
QString locate(QStandardPaths::StandardLocation type, const QString &fileName, QStandardPaths::LocateOptions options)
bool exists() const const
void setModal(bool modal)
void setMinimumSize(const QSize &)
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
bool load(QIODevice *device, const char *format)
virtual QString fileName() const const override
KStarsDateTime addSecs(double s) const
void addWidget(QWidget *widget, int stretch, Qt::Alignment alignment)
void setMaximumWidth(int maxw)
static KStars * Instance()
Definition: kstars.h:125
bool begin(QPaintDevice *device)
void showMessage(const QString &message, int timeout)
QMap::iterator insert(const Key &key, const T &value)
bool isVisible() const const
void addItems(const QStringList &texts)
float fov()
Definition: skymap.cpp:1206
void deleteLater()
void start(int msec)
void setSingleStep(int val)
bool end()
KeepAspectRatio
void setRange(int min, int max)
QString i18n(const char *text, const TYPE &arg...)
void setWindowFlags(Qt::WindowFlags type)
char * toString(const T &value)
void setTracking(bool enable)
QList< T > mid(int pos, int length) const const
void setX(int x)
void setY(int y)
Horizontal
bool isEmpty() const const
Qt::MouseButtons buttons() const const
GeoLocation * geo()
Definition: kstarsdata.h:229
void setWindowTitle(const QString &)
void kill()
const T & at(int i) const const
QUuid createUuid()
void setFileName(const QString &name)
AKONADI_CALENDAR_EXPORT KCalendarCore::Event::Ptr event(const Akonadi::Item &item)
GeoCoordinates geo(const QVariant &location)
void setMaximumSize(const QSize &)
int indexOf(QStringView str, int from) const const
virtual void wheelEvent(QWheelEvent *event)
void setColor(QPalette::ColorGroup group, QPalette::ColorRole role, const QColor &color)
XPlanetImageViewer(const QString &obj, QWidget *parent=nullptr)
Create xplanet image viewer from Object.
QString & replace(int position, int n, QChar after)
PinchGesture
QStatusBar * statusBar() const const
void show()
void setFuture(const QFuture< T > &future)
void setIcon(const QIcon &icon)
QString toLower() const const
void resize(int w, int h)
Qt::MouseEventSource source() const const
int height() const const
Dialog for adjusting the Time and Date.
Definition: timedialog.h:37
QList< Key > keys() const const
void setToolTip(const QString &)
void setSpacing(int spacing)
void stop()
void setValue(int val)
void grabGesture(Qt::GestureType gesture, Qt::GestureFlags flags)
QPoint globalPos() const const
QDate date() const const
void invertPixels(QImage::InvertMode mode)
void setRange(int minimum, int maximum)
void setContentsMargins(int left, int top, int right, int bottom)
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString toString(Qt::DateFormat format) const const
QString toString(Qt::DateFormat format) const const
void setAutoFillBackground(bool enabled)
void addItem(const QString &text, const QVariant &userData)
bool loadImage()
loadImage Load image and display it
void restoreOverrideCursor()
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
QString toString(Qt::DateFormat format) const const
void setInterval(int msec)
void setLayout(QLayout *layout)
MouseEventSynthesizedBySystem
SmoothTransformation
bool save(const QString &fileName, const char *format, int quality) const const
WA_DeleteOnClose
XPlanet Image viewer QFrame for the KPlanetImageViewer for KStars.
void finished(int result)
int width() const const
void accept()
int width() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Sat Aug 13 2022 04:02:01 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.