Kstars

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

KDE's Doxygen guidelines are available online.