diff --git a/kstars/auxiliary/xplanetimageviewer.h b/kstars/auxiliary/xplanetimageviewer.h --- a/kstars/auxiliary/xplanetimageviewer.h +++ b/kstars/auxiliary/xplanetimageviewer.h @@ -28,7 +28,6 @@ #include #include #include -#include #include "kstarsdata.h" #include #include @@ -120,20 +119,15 @@ void startXplanet(); private: - /** - * Display the downloaded image. Resize the window to fit the image, If the image is - * larger than the screen, make the image as large as possible while preserving the - * original aspect ratio - */ - bool showImage(); + /** prepares the output file**/ bool setupOutputFile(); QImage image; /** Save the downloaded image to a local file. */ - void saveFile(QUrl &url); + void saveFile(QString &fileName); QFile file; @@ -144,26 +138,43 @@ XPlanetImageLabel *m_View { nullptr }; QLabel *m_Caption { nullptr }; - QUrl lastURL; + QString lastFile; + + typedef enum { + SUN,MERCURY,VENUS, + EARTH,MOON, + MARS,PHOBOS,DEIMOS, + JUPITER,GANYMEDE,IO,CALLISTO,EUROPA, + SATURN,TITAN,MIMAS,ENCELADUS,TETHYS,DIONE,RHEA,HYPERION,IAPETUS,PHOEBE, + URANUS,UMBRIEL,ARIEL,MIRANDA,TITANIA,OBERON, + NEPTUNE,TRITON } objects; + + QStringList objectNames; typedef enum { YEARS, MONTHS, DAYS, HOURS, MINS, SECS } timeUnits; void setXPlanetDate(KStarsDateTime time); //XPlanet strings - QString object; - QString origin; + QString objectName; + QString originName; QString date; QString dateText; //XPlanet numbers + int currentObject; + int currentOrigin; int rotation; int timeUnit; int radius; double FOV; double lat; double lon; +#ifndef Q_OS_WIN + QFutureWatcher fifoImageLoadWatcher; +#endif + // Time KStarsDateTime xplanetTime; bool xplanetRunning = false; @@ -183,6 +194,7 @@ QLabel *lonDisplay {nullptr}; QLabel *radDisplay {nullptr}; QPushButton *freeRotate {nullptr}; + bool imageLoadSucceeded; // Time controls QLabel *XPlanetTimeDisplay {nullptr}; @@ -197,6 +209,13 @@ private slots: + /** + * Display the downloaded image. Resize the window to fit the image, If the image is + * larger than the screen, make the image as large as possible while preserving the + * original aspect ratio + */ + bool showImage(); + // Saves file to disk. void saveFileToDisk(); @@ -222,8 +241,8 @@ // Time slots void updateXPlanetTime(int timeShift); - void updateXPlanetObject(const QString & obj); - void updateXPlanetOrigin(const QString & obj); + void updateXPlanetObject(int obj); + void updateXPlanetOrigin(int obj); void updateXPlanetTimeUnits(int units); void updateXPlanetTimeEdit(); void setXPlanetTime(); diff --git a/kstars/auxiliary/xplanetimageviewer.cpp b/kstars/auxiliary/xplanetimageviewer.cpp --- a/kstars/auxiliary/xplanetimageviewer.cpp +++ b/kstars/auxiliary/xplanetimageviewer.cpp @@ -169,15 +169,14 @@ XPlanetImageViewer::XPlanetImageViewer(const QString &obj, QWidget *parent): QDialog(parent) { #ifndef KSTARS_LITE - lastURL = QUrl::fromLocalFile(QDir::homePath()); + lastFile = QDir::homePath(); - object=obj; #ifdef Q_OS_OSX setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint); #endif setAttribute(Qt::WA_DeleteOnClose, true); setModal(false); - setWindowTitle(i18n("XPlanet Solar System Simulator: %1", object)); + setWindowTitle(i18n("XPlanet Solar System Simulator: %1", obj)); setXPlanetDate(KStarsData::Instance()->ut()); if (Options::xplanetFOV()) @@ -198,31 +197,34 @@ selectorsLayout->setMargin(0); mainLayout->addWidget(selectorsWidget); - QStringList objects; - objects << i18n("Sun") << i18n("Mercury") << i18n("Venus"); - objects << i18n("Earth") << i18n("Moon"); - objects << i18n("Mars") << i18n("Phobos") << i18n("Deimos"); - objects << i18n("Jupiter") << i18n("Ganymede") << i18n("Io") << i18n("Callisto") << i18n("Europa"); - objects << i18n("Saturn") << i18n("Titan") << i18n("Mimas") << i18n("Enceladus") << i18n("Tethys") << i18n("Dione") << i18n("Rhea") << i18n("Hyperion") << i18n("Iapetus") << i18n("Phoebe"); - objects << i18n("Uranus") << i18n("Umbriel") << i18n("Ariel") << i18n("Miranda") << i18n("Titania") << i18n("Oberon"); - objects << i18n("Neptune") << i18n("Triton"); + objectNames << i18n("Sun") << i18n("Mercury") << i18n("Venus"); + objectNames << i18n("Earth") << i18n("Moon"); + objectNames << i18n("Mars") << i18n("Phobos") << i18n("Deimos"); + objectNames << i18n("Jupiter") << i18n("Ganymede") << i18n("Io") << i18n("Callisto") << i18n("Europa"); + objectNames << i18n("Saturn") << i18n("Titan") << i18n("Mimas") << i18n("Enceladus") << i18n("Tethys") << i18n("Dione") << i18n("Rhea") << i18n("Hyperion") << i18n("Iapetus") << i18n("Phoebe"); + objectNames << i18n("Uranus") << i18n("Umbriel") << i18n("Ariel") << i18n("Miranda") << i18n("Titania") << i18n("Oberon"); + objectNames << i18n("Neptune") << i18n("Triton"); + + currentObject = objectNames.indexOf(obj); + objectName = objectNames.at(currentObject); QComboBox *objectSelector = new QComboBox(this); - objectSelector->addItems(objects); + objectSelector->addItems(objectNames); objectSelector->setToolTip(i18n("This allows you to select a new object/target for XPlanet to view")); selectorsLayout->addWidget(objectSelector); - objectSelector->setCurrentIndex(objectSelector->findText(object)); - connect(objectSelector, SIGNAL(currentTextChanged(QString)), this, SLOT(updateXPlanetObject(QString))); + objectSelector->setCurrentIndex(currentObject); + connect(objectSelector, SIGNAL(currentIndexChanged(int)), this, SLOT(updateXPlanetObject(int))); - origin = i18n("Earth"); + currentOrigin = EARTH; + originName = objectNames.at(EARTH); selectorsLayout->addWidget(new QLabel(i18n("from"),this)); originSelector = new QComboBox(this); - originSelector->addItems(objects); + originSelector->addItems(objectNames); originSelector->setToolTip(i18n("This allows you to select a viewing location")); selectorsLayout->addWidget(originSelector); - originSelector->setCurrentIndex(originSelector->findText(origin)); - connect(originSelector, SIGNAL(currentTextChanged(QString)), this, SLOT(updateXPlanetOrigin(QString))); + originSelector->setCurrentIndex(EARTH); + connect(originSelector, SIGNAL(currentIndexChanged(int)), this, SLOT(updateXPlanetOrigin(int))); lat = Options::xplanetLatitude().toDouble(); lon = Options::xplanetLongitude().toDouble(); @@ -441,7 +443,7 @@ m_Caption = new QLabel(page); m_Caption->setAutoFillBackground(true); m_Caption->setFrameShape(QFrame::StyledPanel); - m_Caption->setText(object); + m_Caption->setText(objectName); // Add layout QVBoxLayout *vlay = new QVBoxLayout(page); vlay->setSpacing(0); @@ -513,7 +515,7 @@ QStringList args; //This specifies the object to be viewed - args << "-body" << object.toLower(); + args << "-body" << objectName.toLower(); //This is the date and time requested args << "-date" << date; //This is the glare from the sun @@ -578,15 +580,15 @@ // This sets the position from which the planet is viewed. // Note that setting Latitude and Longitude means that position above the SAME object - if(object == origin) + if(currentObject == currentOrigin) { if (Options::xplanetRandom()) args << "-random"; else args << "-latitude" << QString::number(lat) << "-longitude" << QString::number(lon) << "-radius" << QString::number(radius); } else - args << "-origin" << origin; + args << "-origin" << originName; // Projection if (Options::xplanetProjection()) @@ -668,57 +670,89 @@ //This prevents it from running forever. args << "-num_times" << "1"; - // Run xplanet - if(Options::xplanetUseFIFO()) - QtConcurrent::run(this, &XPlanetImageViewer::loadImage); + xplanetRunning = true; + imageLoadSucceeded = false; //This will be set to true if it works. + int timeout = Options::xplanetTimeout(); + + //FIFO files don't work on windows + #ifndef Q_OS_WIN + if(Options::xplanetUseFIFO()) + { + fifoImageLoadWatcher.setFuture(QtConcurrent::run(this, &XPlanetImageViewer::loadImage)); + QTimer::singleShot(timeout,&fifoImageLoadWatcher,SLOT(cancel())); + connect(&fifoImageLoadWatcher,SIGNAL(finished()),this,SLOT(showImage())); + } + #endif + xplanetProc->start(xPlanetLocation, args); + //Uncomment to print the XPlanet commands to the console // qDebug() << "Run:" << xplanetProc->program() << args.join(" "); - xplanetRunning = true; - bool succeeded = xplanetProc->waitForFinished(Options::xplanetTimeout().toInt()); + + bool XPlanetSucceeded = xplanetProc->waitForFinished(timeout); xplanetRunning = false; + xplanetProc->kill(); //In case it timed out xplanetProc->deleteLater(); - if(succeeded) + if(XPlanetSucceeded) { if(FOV == 0) - m_Caption->setText(i18n("XPlanet View: ") + object + i18n(" from ") + origin + ", " + dateText); + m_Caption->setText(i18n("XPlanet View: %1 from %2 on %3", objectName, originName, dateText)); else - m_Caption->setText(i18n("XPlanet View: ") + object + i18n(" from ") + origin + ", " + dateText + i18n(", FOV: ") + QString::number(FOV)); - if(!Options::xplanetUseFIFO()) - loadImage(); - showImage(); - } -} + m_Caption->setText(i18n("XPlanet View: %1 from %2 on %3 at FOV: %4 deg", objectName, originName, dateText, FOV)); + #ifdef Q_OS_WIN + loadImage(); //This will also set imageLoadSucceeded based on whether it worked. + #else + if(Options::xplanetUseFIFO()) + return; //This is handled with the watcher + else + loadImage(); //This will also set imageLoadSucceeded based on whether it worked. + #endif -bool XPlanetImageViewer::setupOutputFile() -{ - if(Options::xplanetUseFIFO()) - { - if(file.fileName().contains("/tmp/xplanetfifo") && file.exists()) - return true; - file.setFileName(QString("/tmp/xplanetfifo%1.png").arg(QUuid::createUuid().toString().mid(1, 8))); - int fd =0; - if ((fd = mkfifo(file.fileName().toLatin1(), S_IRUSR | S_IWUSR) < 0)) + if(imageLoadSucceeded) + showImage(); + else { - KMessageBox::error(nullptr, i18n("Error making FIFO file %1: %2.", file.fileName(), strerror(errno))); - return false; + QString text = i18n("Loading of the image of object %1 failed.", objectName); + KMessageBox::error(this, text); } } else { - QDir writableDir; - QString xPlanetDirPath = KSPaths::writableLocation(QStandardPaths::GenericDataLocation) + "xplanet"; - writableDir.mkpath(xPlanetDirPath); - file.setFileName(xPlanetDirPath + QDir::separator() + object + ".png"); + QString text = i18n("XPlanet Failed to generate the image for object %1 before the timeout expired. Perhaps you need a longer timeout or there is something wrong with your XPlanet installation?", objectName); + KMessageBox::error(this, text); } +} +bool XPlanetImageViewer::setupOutputFile() +{ + #ifndef Q_OS_WIN + if(Options::xplanetUseFIFO()) + { + if(file.fileName().contains("xplanetfifo") && file.exists()) + return true; + file.setFileName(KSPaths::writableLocation(QStandardPaths::TempLocation) + QString("xplanetfifo%1.png").arg(QUuid::createUuid().toString().mid(1, 8)).toLatin1()); + int fd =0; + if ((fd = mkfifo(file.fileName().toLatin1(), S_IRUSR | S_IWUSR) < 0)) + { + KMessageBox::error(nullptr, i18n("Error making FIFO file %1: %2.", file.fileName(), strerror(errno))); + return false; + } + return true; + } + #endif + + //If the user is using windows or has not selected to use FIFO, it uses files in the KStars data directory. + QDir writableDir; + QString xPlanetDirPath = KSPaths::writableLocation(QStandardPaths::GenericDataLocation) + "xplanet"; + writableDir.mkpath(xPlanetDirPath); + file.setFileName(xPlanetDirPath + QDir::separator() + objectName + ".png"); return true; } void XPlanetImageViewer::zoomInXPlanetFOV() { - if(origin == object) + if(currentObject == currentOrigin) { radius += 5; radDisplay->setText(QString::number(radius)); @@ -734,7 +768,7 @@ void XPlanetImageViewer::zoomOutXPlanetFOV() { - if(origin == object) + if(currentObject == currentOrigin) { if(radius > 0) { @@ -787,20 +821,22 @@ startXplanet(); } -void XPlanetImageViewer::updateXPlanetObject(const QString &obj){ - object = obj; +void XPlanetImageViewer::updateXPlanetObject(int obj){ + currentObject = obj; + objectName = objectNames.at(obj); - setWindowTitle(i18n("XPlanet Solar System Simulator: %1", object)); + setWindowTitle(i18n("XPlanet Solar System Simulator: %1", objectName)); if(freeRotate->isChecked()) - originSelector->setCurrentIndex(originSelector->findText(object)); + originSelector->setCurrentIndex(currentObject); startXplanet(); } -void XPlanetImageViewer::updateXPlanetOrigin(const QString &obj) +void XPlanetImageViewer::updateXPlanetOrigin(int obj) { - origin = obj; - if(object == origin) + currentOrigin = obj; + originName = objectNames.at(obj); + if(currentObject == currentOrigin) freeRotate->setChecked(true); else freeRotate->setChecked(false); @@ -810,7 +846,7 @@ void XPlanetImageViewer::changeXPlanetPosition(QPoint delta) { - if(origin == object) + if(currentObject == currentOrigin) { double newLon = lon + delta.x(); double newLat = lat + delta.y(); @@ -832,9 +868,9 @@ void XPlanetImageViewer::slotFreeRotate() { if(freeRotate->isChecked()) - originSelector->setCurrentIndex(originSelector->findText(object)); + originSelector->setCurrentIndex(currentObject); else - originSelector->setCurrentIndex(originSelector->findText(i18n("Earth"))); + originSelector->setCurrentIndex(EARTH); } void XPlanetImageViewer::updateStates() @@ -1002,14 +1038,16 @@ bool XPlanetImageViewer::loadImage() { #ifndef KSTARS_LITE + if (!image.load(file.fileName())) { - QString text = i18n("Loading of the image of object %1 failed.", object); - KMessageBox::error(this, text); + imageLoadSucceeded = false; return false; } + imageLoadSucceeded = true; return true; #else + imageLoadSucceeded = false; return false; #endif } @@ -1068,44 +1106,44 @@ void XPlanetImageViewer::saveFileToDisk() { #ifndef KSTARS_LITE - - QUrl newURL = QFileDialog::getSaveFileUrl(KStars::Instance(), i18n("Save Image"), lastURL); // save-dialog with default filename - if (!newURL.isEmpty()) + QString newFileName = QFileDialog::getSaveFileName(KStars::Instance(), i18n("Save Image"), lastFile); // save-dialog with default filename + if (!newFileName.isEmpty()) { - if (newURL.toLocalFile().endsWith(QLatin1String(".png")) == false) - newURL.setPath(newURL.toLocalFile() + ".png"); + if (newFileName.endsWith(QLatin1String(".png")) == false) + newFileName + ".png"; - QFile f(newURL.toLocalFile()); + QFile f(newFileName); if (f.exists()) { int r = KMessageBox::warningContinueCancel(parentWidget(), i18n("A file named \"%1\" already exists. " "Overwrite it?", - newURL.fileName()), + newFileName), i18n("Overwrite File?"), KStandardGuiItem::overwrite()); if (r == KMessageBox::Cancel) return; f.remove(); } - lastURL = QUrl(newURL.toString(QUrl::RemoveFilename)); + lastFile = newFileName; - saveFile(newURL); + saveFile(newFileName); } #endif } -void XPlanetImageViewer::saveFile(QUrl &url) +void XPlanetImageViewer::saveFile(QString &fileName) { #ifndef KSTARS_LITE - if (file.copy(url.toLocalFile()) == false) + + if (! image.save(fileName, "png")) { - QString text = i18n("Saving of the image %1 failed.", url.toString()); + QString text = i18n("Saving of the image to %1 failed.", fileName); KMessageBox::error(this, text); } else - KStars::Instance()->statusBar()->showMessage(i18n("Saved image to %1", url.toString())); + KStars::Instance()->statusBar()->showMessage(i18n("Saved image to %1", fileName)); #endif } diff --git a/kstars/kstars.kcfg b/kstars/kstars.kcfg --- a/kstars/kstars.kcfg +++ b/kstars/kstars.kcfg @@ -1078,7 +1078,7 @@ Option to use a FIFO file instead of saving to the hard disk true - + How long to wait for XPlanet before giving up in milliseconds 1000 diff --git a/kstars/xplanet/opsxplanet.cpp b/kstars/xplanet/opsxplanet.cpp --- a/kstars/xplanet/opsxplanet.cpp +++ b/kstars/xplanet/opsxplanet.cpp @@ -95,6 +95,13 @@ if (Options::xplanetProjection() == 0) groupBoxBackground->setEnabled(false); + #ifdef Q_OS_WIN + kcfg_XplanetUseFIFO->setChecked(false); + kcfg_XplanetUseFIFO->setDisabled(true); + kcfg_XplanetUseFIFO->setToolTip(i18n("FIFO files are not supported on Windows")); + #endif + + connect(openXPlanetMaps, SIGNAL(clicked()),this,SLOT(showXPlanetMapsDirectory())); } diff --git a/kstars/xplanet/opsxplanet.ui b/kstars/xplanet/opsxplanet.ui --- a/kstars/xplanet/opsxplanet.ui +++ b/kstars/xplanet/opsxplanet.ui @@ -428,7 +428,7 @@ - XPlanet Requires Maps in order to function properly. It does not ship with a lot of planetary maps. You need to download some in order to get the full benefits of XPlanet. This is a good place to start: <a href =http://xplanet.sourceforge.net/maps.php>http://xplanet.sourceforge.net/maps.php</a> + XPlanet Requires Maps in order to function properly. It does not ship with a lot of planetary maps. You need to download some in order to get the full benefits of XPlanet. This is a good place to start: <a href="http://xplanet.sourceforge.net/maps.php">http://xplanet.sourceforge.net/maps.php</a> true