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) + QDir::separator() + qAppName());
787  kstarsTempDir.mkpath(".");
788  m_File.setFileName(kstarsTempDir.filePath(QString("xplanetfifo%1.png").arg(QUuid::createUuid().toString().mid(1, 8)).toLatin1()));
789  if (mkfifo(m_File.fileName().toLatin1(), S_IRUSR | S_IWUSR) < 0)
790  {
791  KSNotification::error(i18n("Error making FIFO file %1: %2.", m_File.fileName(), strerror(errno)));
792  return false;
793  }
794  return true;
795  }
796 #endif
797 
798  //If the user is using windows or has not selected to use FIFO, it uses files in the KStars data directory.
799  QDir xPlanetDirPath(KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + QDir::separator() + "xplanet");
800  xPlanetDirPath.mkpath(".");
801  m_File.setFileName(xPlanetDirPath.filePath(m_ObjectName + ".png"));
802  return true;
803 }
804 
805 void XPlanetImageViewer::zoomInXPlanetFOV()
806 {
807  if(m_CurrentObjectIndex == m_CurrentOriginIndex)
808  {
809  m_Radius += 5;
810  updatePositionDisplay();
811  startXplanet();
812  }
813  else
814  {
815  m_FOVEdit->stepDown();
816  startXplanet();
817  }
818 
819 }
820 
821 void XPlanetImageViewer::zoomOutXPlanetFOV()
822 {
823  if(m_CurrentObjectIndex == m_CurrentOriginIndex)
824  {
825  if(m_Radius > 0)
826  {
827  m_Radius -= 5;
828  updatePositionDisplay();
829  startXplanet();
830  }
831  }
832  else
833  {
834  m_FOVEdit->stepUp();
835  startXplanet();
836  }
837 
838 }
839 
840 void XPlanetImageViewer::updatePositionDisplay()
841 {
842  m_PositionDisplay->setText(i18n("%1, %2, %3", QString::number(m_lat), QString::number(m_lon), QString::number(m_Radius)));
843 }
844 
845 void XPlanetImageViewer::updateXPlanetTime(int timeShift)
846 {
847 
848  KStarsDateTime shiftedXPlanetTime;
849  switch(m_CurrentTimeUnitIndex)
850  {
851  case YEARS:
852  shiftedXPlanetTime = m_XPlanetTime.addDays(timeShift * 365);
853  break;
854 
855  case MONTHS:
856  shiftedXPlanetTime = m_XPlanetTime.addDays(timeShift * 30);
857  break;
858 
859  case DAYS:
860  shiftedXPlanetTime = m_XPlanetTime.addDays(timeShift);
861  break;
862 
863  case HOURS:
864  shiftedXPlanetTime = m_XPlanetTime.addSecs(timeShift * 3600);
865  break;
866 
867  case MINS:
868  shiftedXPlanetTime = m_XPlanetTime.addSecs(timeShift * 60);
869  break;
870 
871  case SECS:
872  shiftedXPlanetTime = m_XPlanetTime.addSecs(timeShift);
873  break;
874  }
875 
876  setXPlanetDate(shiftedXPlanetTime);
877  m_DateText = i18n("%1, %2", shiftedXPlanetTime.date().toString(), shiftedXPlanetTime.time().toString());
878  if(m_TimeEdit->value() != timeShift)
879  m_TimeEdit->setValue(timeShift);
880  else
881  startXplanet();
882 }
883 
884 void XPlanetImageViewer::updateXPlanetObject(int objectIndex)
885 {
886  center = QPoint(0, 0);
887  m_CurrentObjectIndex = objectIndex;
888  m_ObjectName = m_ObjectNames.at(objectIndex);
889 
890  setWindowTitle(i18nc("@title:window", "XPlanet Solar System Simulator: %1", m_ObjectName));
891  if(m_FreeRotate->isChecked())
892  m_OriginSelector->setCurrentIndex(m_CurrentObjectIndex);
893  if(m_CurrentObjectIndex == m_CurrentOriginIndex)
894  startXplanet();
895  else
896  resetXPlanetFOV();
897 }
898 
899 void XPlanetImageViewer::updateXPlanetOrigin(int originIndex)
900 {
901  center = QPoint(0, 0);
902  m_CurrentOriginIndex = originIndex;
903  m_OriginName = m_ObjectNames.at(originIndex);
904  if(m_CurrentObjectIndex == m_CurrentOriginIndex)
905  m_FreeRotate->setChecked(true);
906  else
907  m_FreeRotate->setChecked(false);
908  updateStates();//This will update the disabled/enabled states
909  startXplanet();
910 }
911 
912 void XPlanetImageViewer::changeXPlanetLocation(QPoint delta)
913 {
914  if(m_CurrentObjectIndex == m_CurrentOriginIndex)
915  {
916  double newLon = m_lon + delta.x();
917  double newLat = m_lat + delta.y();
918 
919  newLat = qBound(-90.0, newLat, 90.0);
920 
921  m_lon = newLon;
922  m_lat = newLat;
923 
924  updatePositionDisplay();
925  startXplanet();
926  }
927 }
928 
929 void XPlanetImageViewer::changeXPlanetPosition(QPoint delta)
930 {
931  center.setX(center.x() + delta.x());
932  center.setY(center.y() + delta.y());
933  startXplanet();
934 }
935 
936 void XPlanetImageViewer::reCenterXPlanet()
937 {
938  center = QPoint(0, 0);
939  startXplanet();
940 }
941 
942 void XPlanetImageViewer::resetLocation()
943 {
944  m_lat = Options::xplanetLatitude().toDouble();
945  m_lon = Options::xplanetLongitude().toDouble();
946  m_Radius = 45;
947  updatePositionDisplay();
948  startXplanet();
949 }
950 
951 void XPlanetImageViewer::slotFreeRotate()
952 {
953  if(m_FreeRotate->isChecked())
954  m_OriginSelector->setCurrentIndex(m_CurrentObjectIndex);
955  else
956  m_OriginSelector->setCurrentIndex(EARTH);
957 }
958 
959 void XPlanetImageViewer::updateStates()
960 {
961  if(m_FreeRotate->isChecked())
962  {
963  m_FOVEdit->setDisabled(true);
964  m_KStarsFOV->setDisabled(true);
965  m_NoFOV->setDisabled(true);
966 
967  m_PositionDisplay->setDisabled(false);
968  }
969  else
970  {
971  m_FOVEdit->setDisabled(false);
972  m_KStarsFOV->setDisabled(false);
973  m_NoFOV->setDisabled(false);
974 
975  m_PositionDisplay->setDisabled(true);
976  }
977 }
978 
979 void XPlanetImageViewer::setXPlanetDate(KStarsDateTime time)
980 {
981  //Note Xplanet uses UT time for everything but we want the labels to all be LT
982  KStarsDateTime utTime = KStarsData::Instance()->geo()->LTtoUT(time);
983  m_Date = utTime.toString(Qt::ISODate)
984  .replace("-", QString(""))
985  .replace("T", ".")
986  .replace(":", QString(""))
987  .replace("Z", QString(""));
988 }
989 
990 void XPlanetImageViewer::updateXPlanetTimeUnits(int units)
991 {
992  m_CurrentTimeUnitIndex = units;
993  updateXPlanetTimeEdit();
994 }
995 
996 void XPlanetImageViewer::updateXPlanetTimeEdit()
997 {
998  if(m_TimeSlider->isSliderDown())
999  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 
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 
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,...
QString toString(const T &enumerator)
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:139
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:121
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:1164
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)
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-2023 The KDE developers.
Generated on Mon May 8 2023 03:57:36 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.