Commit 9d55dacb authored by Robert Lancaster's avatar Robert Lancaster Committed by Jasem Mutlaq

OSX startup wizard changes

parent ea4edb27
......@@ -398,6 +398,8 @@ if(NOT BUILD_KSTARS_LITE)
dialogs/wizwelcome.ui
dialogs/wizlocation.ui
dialogs/wizdownload.ui
dialogs/wizdata.ui
dialogs/wizastrometry.ui
dialogs/newfov.ui
dialogs/exportimagedialog.ui
)
......
......@@ -34,6 +34,9 @@
#include <cmath>
#include "auxiliary/kspaths.h"
#include "kswizard.h"
#include <QPointer>
namespace KSUtils {
......@@ -634,39 +637,28 @@ bool copyDataFolderFromAppBundleIfNeeded() //The method returns true if the dat
{
QString dataLocation=QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kstars", QStandardPaths::LocateDirectory);
if(dataLocation.isEmpty()) { //If there is no kstars user data directory
if (KMessageBox::warningYesNo(0,
i18n("There is not a KStars User Data Directory currently at ~/Library/Application Support/kstars \n" \
"Do you want to create a new one?"),
i18n("KStars User Data Directory Error."))
== KMessageBox::No) {
return false;
} else {
QString dataSourceLocation=QDir(QCoreApplication::applicationDirPath()+"/../Resources/data").absolutePath();
if(dataSourceLocation.isEmpty()){ //If there is no default data directory in the app bundle
KMessageBox::sorry(0, i18n("Error! There was no default data directory found in the app bundle!"));
return false;
}
QDir writableDir;
writableDir.mkdir(KSPaths::writableLocation(QStandardPaths::GenericDataLocation));
dataLocation=QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kstars", QStandardPaths::LocateDirectory);
if(dataLocation.isEmpty()){ //If there *still* is not a kstars data directory
KMessageBox::sorry(0, i18n("Error! There was a problem creating the data directory ~/Library/Application Support/ !"));
return false;
}
KSUtils::copyRecursively(dataSourceLocation, dataLocation);
Options::setIndiServerIsInternal(true);
Options::setIndiDriversAreInternal(true);
Options::setAstrometrySolverIsInternal(true);
Options::setAstrometryConfFileIsInternal(true);
Options::setWcsIsInternal(true);
Options::setXplanetIsInternal(true);
KMessageBox::sorry(0, "KStars User Data Directory created at: " + dataLocation);
if (KMessageBox::warningYesNo(0,i18n("Do you want to set up the internal Astrometry.net for plate solving images?"))== KMessageBox::Yes)
configureDefaultAstrometry();
return true; //This means the data directory is good to go now that we created it from the default.
}
QPointer<KSWizard> wizard = new KSWizard(new QFrame());
wizard->exec();//This will pause the startup until the user installs the data directory from the Wizard.
dataLocation=QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kstars", QStandardPaths::LocateDirectory);
if(dataLocation.isEmpty())
return false;
//This sets some important OS X options.
Options::setIndiServerIsInternal(true);
Options::setIndiDriversAreInternal(true);
Options::setAstrometrySolverIsInternal(true);
Options::setAstrometryConfFileIsInternal(true);
Options::setWcsIsInternal(true);
Options::setXplanetIsInternal(true);
Options::setRunStartupWizard( false ); //don't run on startup because we are doing it now.
return true; //This means the data directory is good to go now that we created it from the default.
}
return true;//This means the data directory was good to go from the start.
return true;//This means the data directory was good to go from the start and the wizard did not run.
}
void configureDefaultAstrometry(){
......@@ -678,9 +670,6 @@ void configureDefaultAstrometry(){
if(astrometryPath.isEmpty())
KMessageBox::sorry(0, i18n("Error! The Astrometry Index File Directory does not exist and was not able to be created."));
else{
if(QDir(astrometryPath).count()<3)
KMessageBox::sorry(0, "Astrometry Index Directory is at: " + astrometryPath +"\n Be sure to put Astrometry index files there in order to solve images.");
QString confPath=QCoreApplication::applicationDirPath()+"/astrometry/bin/astrometry.cfg";
QFile confFile(confPath);
QString contents;
......
......@@ -16,7 +16,7 @@
***************************************************************************/
#include "kswizard.h"
#include "ksutils.h"
#include <QFile>
#include <QStackedWidget>
#include <QPixmap>
......@@ -24,6 +24,8 @@
#include <QPushButton>
#include <kns3/downloaddialog.h>
#include <QStandardPaths>
#include <QDesktopServices>
#include <QProcess>
#include "kspaths.h"
#include "kstarsdata.h"
......@@ -50,6 +52,15 @@ WizDownloadUI::WizDownloadUI( QWidget *parent ) : QFrame( parent ) {
setupUi( this );
}
#ifdef Q_OS_OSX
WizDataUI::WizDataUI( QWidget *parent ) : QFrame( parent ) {
setupUi( this );
}
WizAstrometryUI::WizAstrometryUI( QWidget *parent ) : QFrame( parent ) {
setupUi( this );
}
#endif
KSWizard::KSWizard( QWidget *parent ) :
QDialog( parent )
{
......@@ -57,7 +68,10 @@ KSWizard::KSWizard( QWidget *parent ) :
setWindowFlags(Qt::Tool| Qt::WindowStaysOnTopHint);
#endif
wizardStack = new QStackedWidget( this );
adjustSize();
setWindowTitle( i18n("Setup Wizard") );
......@@ -65,7 +79,7 @@ KSWizard::KSWizard( QWidget *parent ) :
mainLayout->addWidget(wizardStack);
setLayout(mainLayout);
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel, Qt::Horizontal);
buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel, Qt::Horizontal);
nextB = new QPushButton(i18n("&Next >"));
nextB->setDefault(true);
backB = new QPushButton(i18n("< &Back"));
......@@ -76,11 +90,21 @@ KSWizard::KSWizard( QWidget *parent ) :
mainLayout->addWidget(buttonBox);
WizWelcomeUI* welcome = new WizWelcomeUI( wizardStack );
#ifdef Q_OS_OSX
data = new WizDataUI( wizardStack );
astrometry = new WizAstrometryUI( wizardStack );
#endif
location = new WizLocationUI( wizardStack );
WizDownloadUI* download = new WizDownloadUI( wizardStack );
wizardStack->addWidget( welcome );
#ifdef Q_OS_OSX
wizardStack->addWidget( data );
wizardStack->addWidget( astrometry );
#endif
wizardStack->addWidget( location );
wizardStack->addWidget( download );
wizardStack->setCurrentWidget( welcome );
......@@ -89,10 +113,41 @@ KSWizard::KSWizard( QWidget *parent ) :
QPixmap im;
if( im.load(KSPaths::locate(QStandardPaths::GenericDataLocation, "wzstars.png")) )
welcome->Banner->setPixmap( im );
else if( im.load(QDir(QCoreApplication::applicationDirPath()+"/../Resources/data").absolutePath()+"/wzstars.png"))
welcome->Banner->setPixmap( im );
if( im.load(KSPaths::locate(QStandardPaths::GenericDataLocation, "wzgeo.png")) )
location->Banner->setPixmap( im );
else if( im.load(QDir(QCoreApplication::applicationDirPath()+"/../Resources/data").absolutePath()+"/wzgeo.png"))
location->Banner->setPixmap( im );
if( im.load(KSPaths::locate(QStandardPaths::GenericDataLocation, "wzdownload.png")) )
download->Banner->setPixmap( im );
else if( im.load(QDir(QCoreApplication::applicationDirPath()+"/../Resources/data").absolutePath()+"/wzdownload.png"))
download->Banner->setPixmap( im );
#ifdef Q_OS_OSX
if( im.load(KSPaths::locate(QStandardPaths::GenericDataLocation, "wzdownload.png")) )
data->Banner->setPixmap( im );
else if( im.load(QDir(QCoreApplication::applicationDirPath()+"/../Resources/data").absolutePath()+"/wzdownload.png"))
data->Banner->setPixmap( im );
if( im.load(KSPaths::locate(QStandardPaths::GenericDataLocation, "wzdownload.png")) )
astrometry->Banner->setPixmap( im );
else if( im.load(QDir(QCoreApplication::applicationDirPath()+"/../Resources/data").absolutePath()+"/wzdownload.png"))
astrometry->Banner->setPixmap( im );
data->dataPath->setText(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QString(), QStandardPaths::LocateDirectory)+"kstars");
updateDataButtons();
astrometry->astrometryPath->setText(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QString(), QStandardPaths::LocateDirectory)+"Astrometry");
updateAstrometryButtons();
connect(data->copyKStarsData, SIGNAL(clicked()), this, SLOT(copyKStarsDataDirectory()));
connect(astrometry->astrometryButton, SIGNAL(clicked()), this, SLOT(slotOpenOrCreateAstrometryFolder()));
connect(astrometry->pipInstall, SIGNAL(clicked()), this, SLOT(slotInstallPip()));
connect(astrometry->pyfitsInstall, SIGNAL(clicked()), this, SLOT(slotInstallPyfits()));
connect(astrometry->netpbmInstall, SIGNAL(clicked()), this, SLOT(slotInstallNetpbm()));
connect(this,SIGNAL(accepted()),this,SLOT(finishWizard()));
#endif
//connect signals/slots
connect(nextB, SIGNAL(clicked()), this, SLOT(slotNextPage()));
......@@ -106,8 +161,10 @@ KSWizard::KSWizard( QWidget *parent ) :
connect( location->CountryFilter, SIGNAL( textChanged( const QString & ) ), this, SLOT( slotFilterCities() ) );
connect( download->DownloadButton, SIGNAL( clicked() ), this, SLOT( slotDownload() ) );
//Initialize Geographic Location page
initGeoPage();
if(KStars::Instance())
initGeoPage();
}
//Do NOT delete members of filteredCityList! They are not created by KSWizard.
......@@ -117,6 +174,21 @@ KSWizard::~KSWizard()
void KSWizard::setButtonsEnabled() {
nextB->setEnabled(wizardStack->currentIndex() < wizardStack->count()-1 );
backB->setEnabled(wizardStack->currentIndex() > 0 );
#ifdef Q_OS_OSX
if((wizardStack->currentWidget()==data) &&(!dataDirExists())){
nextB->setEnabled(false);
buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
}
if(wizardStack->currentWidget()==location){
if(KStars::Instance()){
if(location->LongBox->isReadOnly()==false){
initGeoPage();
}
}
}
#endif
}
void KSWizard::slotNextPage() {
......@@ -191,3 +263,189 @@ void KSWizard::slotDownload() {
}
void KSWizard::finishWizard(){
KStars::Instance()->updateLocationFromWizard(*(geo()));
delete this;
}
#ifdef Q_OS_OSX
void KSWizard::copyKStarsDataDirectory(){
QString dataSourceLocation=QDir(QCoreApplication::applicationDirPath()+"/../Resources/data").absolutePath();
if(dataSourceLocation.isEmpty()){ //If there is no default data directory in the app bundle
KMessageBox::sorry(0, i18n("Error! There was no default data directory found in the app bundle!"));
return;
}
QDir writableDir;
writableDir.mkdir(KSPaths::writableLocation(QStandardPaths::GenericDataLocation));
QString dataLocation=QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kstars", QStandardPaths::LocateDirectory);
if(dataLocation.isEmpty()){ //If there *still* is not a kstars data directory
KMessageBox::sorry(0, i18n("Error! There was a problem creating the data directory ~/Library/Application Support/ !"));
return;
}
KSUtils::copyRecursively(dataSourceLocation, dataLocation);
updateDataButtons();
//This will let the program load after the data folder is copied
hide();
setModal(false);
show();
//Enable the buttons so you can go to the next page or click ok.
nextB->setEnabled(true);
buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
}
void KSWizard::slotOpenOrCreateAstrometryFolder()
{
QString astrometryLocation=QStandardPaths::locate(QStandardPaths::GenericDataLocation, "Astrometry", QStandardPaths::LocateDirectory);
if(astrometryLocation.isEmpty()) {
KSUtils::configureDefaultAstrometry();
updateAstrometryButtons();
} else{
QUrl path = QUrl::fromLocalFile(QStandardPaths::locate(QStandardPaths::GenericDataLocation, "Astrometry", QStandardPaths::LocateDirectory));
QDesktopServices::openUrl(path);
}
}
void KSWizard::slotInstallPip()
{
if(!pythonExists()){
KMessageBox::sorry(0,"Python is not installed. Please install python to /usr/local/bin first.");
}else{
if(!pipExists()){
QProcess* install = new QProcess();
connect(install, SIGNAL(finished(int)), this, SLOT(updateAstrometryButtons()));
install->start("easy_install" , QStringList() << "pip");
}
}
}
void KSWizard::slotInstallPyfits()
{
if(!pythonExists()){
KMessageBox::sorry(0,"Python is not installed. Please install python to /usr/local/bin first.");
}else if(!pipExists()){
KMessageBox::sorry(0,"Pip is not installed. Please install pip first.");
} else{
QProcess* install = new QProcess();
connect(install, SIGNAL(finished(int)), this, SLOT(updateAstrometryButtons()));
install->start("pip" , QStringList() << "install" << "pyfits");
}
}
void KSWizard::slotInstallNetpbm()
{
QProcess* install = new QProcess();
connect(install, SIGNAL(finished(int)), this, SLOT(updateAstrometryButtons()));
if(brewExists()){
install->start("brew" , QStringList() << "install" << "netpbm");
} else{
install->start("ruby", QStringList() << "-e" << "'$(curl -fsSL raw.githubusercontent.com/Homebrew/install/master/install)'" << "<" << "/dev/null" << "2>" << "/dev/null");
install->waitForFinished();
install->start("brew" , QStringList() << "install" << "netpbm");
}
}
bool KSWizard::dataDirExists(){
QString dataLocation=QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kstars", QStandardPaths::LocateDirectory);
return !dataLocation.isEmpty();
}
bool KSWizard::astrometryDirExists(){
QString astrometryLocation=QStandardPaths::locate(QStandardPaths::GenericDataLocation, "Astrometry", QStandardPaths::LocateDirectory);
return !astrometryLocation.isEmpty();
}
bool KSWizard::pythonExists(){
return QProcess::execute("type python")==QProcess::NormalExit;
}
bool KSWizard::pipExists(){
return QProcess::execute("type pip")==QProcess::NormalExit;
}
bool KSWizard::pyfitsExists(){
QProcess testPyfits;
testPyfits.start("pip list");
testPyfits.waitForFinished();
QString listPip(testPyfits.readAllStandardOutput());
qDebug()<<listPip;
return listPip.contains("pyfits", Qt::CaseInsensitive);
}
bool KSWizard::netpbmExists(){
return QProcess::execute("type jpegtopnm")==QProcess::NormalExit;
}
bool KSWizard::brewExists(){
return QProcess::execute("type brew")==QProcess::NormalExit;
}
void KSWizard::updateDataButtons(){
if(dataDirExists()) {
data->dataDirFound->setChecked(true);
data->copyKStarsData->setDisabled(true);
data->foundFeedback1->setText("The KStars Data Directory called kstars is located at:");
data->foundFeedback2->setText("Your data directory was found. If you have any problems with it, you can always delete this data directory and KStars will give you a new data directory.");
} else{
data->dataDirFound->setChecked(false);
data->copyKStarsData->setDisabled(false);
data->foundFeedback1->setText("The KStars Data Directory called kstars should be located at:");
data->foundFeedback2->setText("Your data directory was not found. You can click the button below to copy a default KStars data directory to the correct location, or if you have a KStars directory already some place else, you can exit KStars and copy it to that location yourself.");
}
}
void KSWizard::updateAstrometryButtons(){
if(astrometryDirExists()) {
astrometry->astrometryFound->setChecked(true);
astrometry->astrometryButton->setText("Open Folder");
astrometry->astrometryFeedback->setText("");
} else{
astrometry->astrometryFound->setChecked(false);
astrometry->astrometryButton->setText("Create Folder");
astrometry->astrometryFeedback->setText("Note: Currently your Astrometry Folder does not exist, please click 'Create Folder' to make it.");
}
if(!pythonExists()){
astrometry->pipFound->setChecked(false);
astrometry->pipInstall->setDisabled(false);
astrometry->pyfitsFound->setChecked(false);
astrometry->pyfitsInstall->setDisabled(false);
}
else{
if(pipExists()){
astrometry->pipFound->setChecked(true);
astrometry->pipInstall->setDisabled(true);
if(pyfitsExists()){
astrometry->pyfitsFound->setChecked(true);
astrometry->pyfitsInstall->setDisabled(true);
}else{
astrometry->pyfitsFound->setChecked(false);
astrometry->pyfitsInstall->setDisabled(false);
}
}else{
astrometry->pipFound->setChecked(false);
astrometry->pipInstall->setDisabled(false);
astrometry->pyfitsFound->setChecked(false);
astrometry->pyfitsInstall->setDisabled(false);
}
}
//Testing a random netpbm command.
if(netpbmExists()){
astrometry->netpbmFound->setChecked(true);
astrometry->netpbmInstall->setDisabled(true);
}else{
astrometry->netpbmFound->setChecked(false);
astrometry->netpbmInstall->setDisabled(false);
}
}
#endif
......@@ -19,10 +19,13 @@
#define KSWIZARD_H_
#include <QDialog>
#include <QDialogButtonBox>
#include "ui_wizwelcome.h"
#include "ui_wizlocation.h"
#include "ui_wizdownload.h"
#include "ui_wizdata.h"
#include "ui_wizastrometry.h"
class GeoLocation;
class QStackedWidget;
......@@ -39,6 +42,18 @@ public:
explicit WizLocationUI( QWidget *parent=0 );
};
class WizDataUI : public QFrame, public Ui::WizData {
Q_OBJECT
public:
explicit WizDataUI( QWidget *parent=0 );
};
class WizAstrometryUI : public QFrame, public Ui::WizAstrometry {
Q_OBJECT
public:
explicit WizAstrometryUI( QWidget *parent=0 );
};
class WizDownloadUI : public QFrame, public Ui::WizDownload {
Q_OBJECT
public:
......@@ -84,7 +99,25 @@ private slots:
*/
void slotFilterCities();
void slotDownload();
void slotDownload();
void finishWizard();
#ifdef Q_OS_OSX
void slotOpenOrCreateAstrometryFolder();
void slotInstallPip();
void slotInstallPyfits();
void slotInstallNetpbm();
void updateAstrometryButtons();
void updateDataButtons();
void copyKStarsDataDirectory();
#endif
private:
/** @short Initialize the geographic location page.
......@@ -97,10 +130,30 @@ private:
QStackedWidget *wizardStack;
WizLocationUI *location;
WizDataUI* data;
WizAstrometryUI* astrometry;
QPushButton *nextB,*backB;
QDialogButtonBox *buttonBox;
GeoLocation *Geo;
QList<GeoLocation*> filteredCityList;
#ifdef Q_OS_OSX
bool brewExists();
bool pythonExists();
bool pipExists();
bool pyfitsExists();
bool netpbmExists();
bool dataDirExists();
bool astrometryDirExists();
#endif
};
#endif
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>WizAstrometry</class>
<widget class="QWidget" name="WizAstrometry">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>711</width>
<height>395</height>
</rect>
</property>
<layout class="QHBoxLayout">
<property name="leftMargin">
<number>8</number>
</property>
<property name="topMargin">
<number>8</number>
</property>
<property name="rightMargin">
<number>8</number>
</property>
<property name="bottomMargin">
<number>8</number>
</property>
<item>
<widget class="QLabel" name="Banner">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>120</width>
<height>360</height>
</size>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout">
<item>
<widget class="QLabel" name="WelcomeTitle">
<property name="font">
<font>
<family>Sans Serif</family>
<pointsize>11</pointsize>
<weight>75</weight>
<italic>false</italic>
<bold>true</bold>
<underline>false</underline>
<strikeout>false</strikeout>
</font>
</property>
<property name="text">
<string>Astrometry Setup for Plate Solving Astronomical Images</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>12</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="WelcomeText">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;KStars makes use of Astrometry.net to plate solve images to aid with telescope alignment. &lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The Mac Version of KStars is bundled with an internal Astrometry.net package. However, to get it to run, you will need to have the following programs installed on your computer. You can click the button to install each of them (still experimental) or you can install them yourself from an installer, from the command line, and/or from homebrew.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QPushButton" name="pipInstall">
<property name="text">
<string>pip</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pyfitsInstall">
<property name="text">
<string>pyfits</string>
</property>