File indexing completed on 2024-04-14 14:11:44

0001 /*
0002     SPDX-FileCopyrightText: 2003 Jason Harris <kstars@30doradus.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "scriptbuilder.h"
0008 
0009 #include "kspaths.h"
0010 #include "scriptfunction.h"
0011 #include "kstars.h"
0012 #include "kstarsdata.h"
0013 #include "skymap.h"
0014 #include "ksnotification.h"
0015 #include "kstarsdatetime.h"
0016 #include "dialogs/finddialog.h"
0017 #include "dialogs/locationdialog.h"
0018 #include "widgets/dmsbox.h"
0019 #include "widgets/timespinbox.h"
0020 #include "widgets/timestepbox.h"
0021 
0022 #include <KLocalizedString>
0023 #include <KMessageBox>
0024 #include <KIO/StoredTransferJob>
0025 #include <KIO/CopyJob>
0026 #include <KJob>
0027 
0028 #include <QApplication>
0029 #include <QFontMetrics>
0030 #include <QTreeWidget>
0031 #include <QTextStream>
0032 #include <QFileDialog>
0033 #include <QStandardPaths>
0034 #include <QTemporaryFile>
0035 #include <QProcess>
0036 #include <QDebug>
0037 
0038 #include <sys/stat.h>
0039 
0040 OptionsTreeViewWidget::OptionsTreeViewWidget(QWidget *p) : QFrame(p)
0041 {
0042     setupUi(this);
0043 }
0044 
0045 OptionsTreeView::OptionsTreeView(QWidget *p) : QDialog(p)
0046 {
0047     otvw.reset(new OptionsTreeViewWidget(this));
0048 
0049     QVBoxLayout *mainLayout = new QVBoxLayout;
0050 
0051     mainLayout->addWidget(otvw.get());
0052     setLayout(mainLayout);
0053 
0054     setWindowTitle(i18nc("@title:window", "Options"));
0055 
0056     QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
0057     mainLayout->addWidget(buttonBox);
0058     connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
0059     connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
0060 
0061     setModal(false);
0062 }
0063 
0064 void OptionsTreeView::resizeColumns()
0065 {
0066     //Size each column to the maximum width of items in that column
0067     int maxwidth[3]  = { 0, 0, 0 };
0068     QFontMetrics qfm = optionsList()->fontMetrics();
0069 
0070     for (int i = 0; i < optionsList()->topLevelItemCount(); ++i)
0071     {
0072         QTreeWidgetItem *topitem = optionsList()->topLevelItem(i);
0073         topitem->setExpanded(true);
0074 
0075         for (int j = 0; j < topitem->childCount(); ++j)
0076         {
0077             QTreeWidgetItem *child = topitem->child(j);
0078 
0079             for (int icol = 0; icol < 3; ++icol)
0080             {
0081                 child->setExpanded(true);
0082 
0083                 int w = qfm.horizontalAdvance(child->text(icol)) + 4;
0084 
0085                 if (icol == 0)
0086                 {
0087                     w += 2 * optionsList()->indentation();
0088                 }
0089 
0090                 if (w > maxwidth[icol])
0091                 {
0092                     maxwidth[icol] = w;
0093                 }
0094             }
0095         }
0096     }
0097 
0098     for (int icol = 0; icol < 3; ++icol)
0099     {
0100         //DEBUG
0101         qDebug() << Q_FUNC_INFO << QString("max width of column %1: %2").arg(icol).arg(maxwidth[icol]);
0102 
0103         optionsList()->setColumnWidth(icol, maxwidth[icol]);
0104     }
0105 }
0106 
0107 ScriptNameWidget::ScriptNameWidget(QWidget *p) : QFrame(p)
0108 {
0109     setupUi(this);
0110 }
0111 
0112 ScriptNameDialog::ScriptNameDialog(QWidget *p) : QDialog(p)
0113 {
0114 #ifdef Q_OS_OSX
0115     setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint);
0116 #endif
0117     snw = new ScriptNameWidget(this);
0118 
0119     QVBoxLayout *mainLayout = new QVBoxLayout;
0120 
0121     mainLayout->addWidget(snw);
0122     setLayout(mainLayout);
0123 
0124     setWindowTitle(i18nc("@title:window", "Script Data"));
0125 
0126     QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
0127     mainLayout->addWidget(buttonBox);
0128     connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
0129     connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
0130 
0131     okB = buttonBox->button(QDialogButtonBox::Ok);
0132 
0133     connect(snw->ScriptName, SIGNAL(textChanged(QString)), this, SLOT(slotEnableOkButton()));
0134 }
0135 
0136 ScriptNameDialog::~ScriptNameDialog()
0137 {
0138     delete snw;
0139 }
0140 
0141 void ScriptNameDialog::slotEnableOkButton()
0142 {
0143     okB->setEnabled(!snw->ScriptName->text().isEmpty());
0144 }
0145 
0146 ScriptBuilderUI::ScriptBuilderUI(QWidget *p) : QFrame(p)
0147 {
0148     setupUi(this);
0149 }
0150 
0151 ScriptBuilder::ScriptBuilder(QWidget *parent)
0152     : QDialog(parent), UnsavedChanges(false), checkForChanges(true), currentFileURL(), currentDir(QDir::homePath()),
0153       currentScriptName(), currentAuthor()
0154 {
0155 #ifdef Q_OS_OSX
0156     setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint);
0157 #endif
0158     sb = new ScriptBuilderUI(this);
0159 
0160     QVBoxLayout *mainLayout = new QVBoxLayout;
0161 
0162     mainLayout->addWidget(sb);
0163     setLayout(mainLayout);
0164 
0165     setWindowTitle(i18nc("@title:window", "Script Builder"));
0166 
0167     QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close);
0168     mainLayout->addWidget(buttonBox);
0169     connect(buttonBox, SIGNAL(rejected()), this, SLOT(slotClose()));
0170 
0171     sb->FuncDoc->setTextInteractionFlags(Qt::NoTextInteraction);
0172 
0173     //Initialize function templates and descriptions
0174     KStarsFunctionList.append(new ScriptFunction("lookTowards",
0175                               i18n("Point the display at the specified location. %1 can be the name "
0176                                    "of an object, a cardinal point on the compass, or 'zenith'.",
0177                                    QString("dir")),
0178                               false, "QString", "dir"));
0179     KStarsFunctionList.append(new ScriptFunction(
0180                                   "addLabel", i18n("Add a name label to the object named %1.", QString("name")), false, "QString", "name"));
0181     KStarsFunctionList.append(
0182         new ScriptFunction("removeLabel", i18n("Remove the name label from the object named %1.", QString("name")),
0183                            false, "QString", "name"));
0184     KStarsFunctionList.append(new ScriptFunction(
0185                                   "addTrail", i18n("Add a trail to the solar system body named %1.", QString("name")), false, "QString", "name"));
0186     KStarsFunctionList.append(new ScriptFunction(
0187                                   "removeTrail", i18n("Remove the trail from the solar system body named %1.", QString("name")), false, "QString",
0188                                   "name"));
0189     KStarsFunctionList.append(new ScriptFunction("setRaDec",
0190                               i18n("Point the display at the specified RA/Dec coordinates.  RA is "
0191                                    "expressed in Hours; Dec is expressed in Degrees."),
0192                               false, "double", "ra", "double", "dec"));
0193     KStarsFunctionList.append(new ScriptFunction(
0194                                   "setAltAz",
0195                                   i18n("Point the display at the specified Alt/Az coordinates.  Alt and Az are expressed in Degrees."), false,
0196                                   "double", "alt", "double", "az"));
0197     KStarsFunctionList.append(new ScriptFunction("zoomIn", i18n("Increase the display Zoom Level."), false));
0198     KStarsFunctionList.append(new ScriptFunction("zoomOut", i18n("Decrease the display Zoom Level."), false));
0199     KStarsFunctionList.append(
0200         new ScriptFunction("defaultZoom", i18n("Set the display Zoom Level to its default value."), false));
0201     KStarsFunctionList.append(
0202         new ScriptFunction("zoom", i18n("Set the display Zoom Level manually."), false, "double", "z"));
0203     KStarsFunctionList.append(
0204         new ScriptFunction("setLocalTime", i18n("Set the system clock to the specified Local Time."), false, "int",
0205                            "year", "int", "month", "int", "day", "int", "hour", "int", "minute", "int", "second"));
0206     KStarsFunctionList.append(new ScriptFunction(
0207                                   "waitFor", i18n("Pause script execution for specified number of seconds."), false, "double", "sec"));
0208     KStarsFunctionList.append(new ScriptFunction("waitForKey",
0209                               i18n("Halt script execution until the specified key is pressed.  Only "
0210                                    "single-key strokes are possible; use 'space' for the spacebar."),
0211                               false, "QString", "key"));
0212     KStarsFunctionList.append(new ScriptFunction(
0213                                   "setTracking", i18n("Set whether the display is tracking the current location."), false, "bool", "track"));
0214     KStarsFunctionList.append(new ScriptFunction(
0215                                   "changeViewOption", i18n("Change view option named %1 to value %2.", QString("opName"), QString("opValue")),
0216                                   false, "QString", "opName", "QString", "opValue"));
0217     KStarsFunctionList.append(new ScriptFunction(
0218                                   "setGeoLocation", i18n("Set the geographic location to the city specified by city, province and country."),
0219                                   false, "QString", "cityName", "QString", "provinceName", "QString", "countryName"));
0220     KStarsFunctionList.append(new ScriptFunction(
0221                                   "setColor", i18n("Set the color named %1 to the value %2.", QString("colorName"), QString("value")), false,
0222                                   "QString", "colorName", "QString", "value"));
0223     KStarsFunctionList.append(new ScriptFunction("loadColorScheme", i18n("Load the color scheme specified by name."),
0224                               false, "QString", "name"));
0225     KStarsFunctionList.append(
0226         new ScriptFunction("exportImage", i18n("Export the sky image to the file, with specified width and height."),
0227                            false, "QString", "fileName", "int", "width", "int", "height"));
0228     KStarsFunctionList.append(
0229         new ScriptFunction("printImage",
0230                            i18n("Print the sky image to a printer or file.  If %1 is true, it will show the print "
0231                                 "dialog.  If %2 is true, it will use the Star Chart color scheme for printing.",
0232                                 QString("usePrintDialog"), QString("useChartColors")),
0233                            false, "bool", "usePrintDialog", "bool", "useChartColors"));
0234     SimClockFunctionList.append(new ScriptFunction("stop", i18n("Halt the simulation clock."), true));
0235     SimClockFunctionList.append(new ScriptFunction("start", i18n("Start the simulation clock."), true));
0236     SimClockFunctionList.append(new ScriptFunction("setClockScale",
0237                                 i18n("Set the timescale of the simulation clock to specified scale. "
0238                                      " 1.0 means real-time; 2.0 means twice real-time; etc."),
0239                                 true, "double", "scale"));
0240 
0241     // JM: We're using QTreeWdiget for Qt4 now
0242     QTreeWidgetItem *kstars_tree   = new QTreeWidgetItem(sb->FunctionTree, QStringList("KStars"));
0243     QTreeWidgetItem *simclock_tree = new QTreeWidgetItem(sb->FunctionTree, QStringList("SimClock"));
0244 
0245     for (auto &item : KStarsFunctionList)
0246         new QTreeWidgetItem(kstars_tree, QStringList(item->prototype()));
0247 
0248     for (auto &item : SimClockFunctionList)
0249         new QTreeWidgetItem(simclock_tree, QStringList(item->prototype()));
0250 
0251     kstars_tree->sortChildren(0, Qt::AscendingOrder);
0252     simclock_tree->sortChildren(0, Qt::AscendingOrder);
0253 
0254     sb->FunctionTree->setColumnCount(1);
0255     sb->FunctionTree->setHeaderLabels(QStringList(i18n("Functions")));
0256     sb->FunctionTree->setSortingEnabled(false);
0257 
0258     //Add icons to Push Buttons
0259     sb->NewButton->setIcon(QIcon::fromTheme("document-new"));
0260     sb->OpenButton->setIcon(QIcon::fromTheme("document-open"));
0261     sb->SaveButton->setIcon(QIcon::fromTheme("document-save"));
0262     sb->SaveAsButton->setIcon(
0263         QIcon::fromTheme("document-save-as"));
0264     sb->RunButton->setIcon(QIcon::fromTheme("system-run"));
0265     sb->CopyButton->setIcon(QIcon::fromTheme("view-refresh"));
0266     sb->AddButton->setIcon(QIcon::fromTheme("go-previous"));
0267     sb->RemoveButton->setIcon(QIcon::fromTheme("go-next"));
0268     sb->UpButton->setIcon(QIcon::fromTheme("go-up"));
0269     sb->DownButton->setIcon(QIcon::fromTheme("go-down"));
0270 
0271     sb->NewButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
0272     sb->OpenButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
0273     sb->SaveButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
0274     sb->SaveAsButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
0275     sb->RunButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
0276     sb->CopyButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
0277     sb->AddButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
0278     sb->RemoveButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
0279     sb->UpButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
0280     sb->DownButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
0281 
0282     //Prepare the widget stack
0283     argBlank            = new QWidget();
0284     argLookToward       = new ArgLookToward(sb->ArgStack);
0285     argFindObject       = new ArgFindObject(sb->ArgStack); //shared by Add/RemoveLabel and Add/RemoveTrail
0286     argSetRaDec         = new ArgSetRaDec(sb->ArgStack);
0287     argSetAltAz         = new ArgSetAltAz(sb->ArgStack);
0288     argSetLocalTime     = new ArgSetLocalTime(sb->ArgStack);
0289     argWaitFor          = new ArgWaitFor(sb->ArgStack);
0290     argWaitForKey       = new ArgWaitForKey(sb->ArgStack);
0291     argSetTracking      = new ArgSetTrack(sb->ArgStack);
0292     argChangeViewOption = new ArgChangeViewOption(sb->ArgStack);
0293     argSetGeoLocation   = new ArgSetGeoLocation(sb->ArgStack);
0294     argTimeScale        = new ArgTimeScale(sb->ArgStack);
0295     argZoom             = new ArgZoom(sb->ArgStack);
0296     argExportImage      = new ArgExportImage(sb->ArgStack);
0297     argPrintImage       = new ArgPrintImage(sb->ArgStack);
0298     argSetColor         = new ArgSetColor(sb->ArgStack);
0299     argLoadColorScheme  = new ArgLoadColorScheme(sb->ArgStack);
0300 
0301     sb->ArgStack->addWidget(argBlank);
0302     sb->ArgStack->addWidget(argLookToward);
0303     sb->ArgStack->addWidget(argFindObject);
0304     sb->ArgStack->addWidget(argSetRaDec);
0305     sb->ArgStack->addWidget(argSetAltAz);
0306     sb->ArgStack->addWidget(argSetLocalTime);
0307     sb->ArgStack->addWidget(argWaitFor);
0308     sb->ArgStack->addWidget(argWaitForKey);
0309     sb->ArgStack->addWidget(argSetTracking);
0310     sb->ArgStack->addWidget(argChangeViewOption);
0311     sb->ArgStack->addWidget(argSetGeoLocation);
0312     sb->ArgStack->addWidget(argTimeScale);
0313     sb->ArgStack->addWidget(argZoom);
0314     sb->ArgStack->addWidget(argExportImage);
0315     sb->ArgStack->addWidget(argPrintImage);
0316     sb->ArgStack->addWidget(argSetColor);
0317     sb->ArgStack->addWidget(argLoadColorScheme);
0318 
0319     sb->ArgStack->setCurrentIndex(0);
0320 
0321     snd = new ScriptNameDialog(KStars::Instance());
0322     otv = new OptionsTreeView(KStars::Instance());
0323 
0324     otv->resize(sb->width(), 0.5 * sb->height());
0325 
0326     initViewOptions();
0327     otv->resizeColumns();
0328 
0329     //connect widgets in ScriptBuilderUI
0330     connect(sb->FunctionTree, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(slotAddFunction()));
0331     connect(sb->FunctionTree, SIGNAL(itemClicked(QTreeWidgetItem*, int)), this, SLOT(slotShowDoc()));
0332     connect(sb->UpButton, SIGNAL(clicked()), this, SLOT(slotMoveFunctionUp()));
0333     connect(sb->ScriptListBox, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(slotArgWidget()));
0334     connect(sb->DownButton, SIGNAL(clicked()), this, SLOT(slotMoveFunctionDown()));
0335     connect(sb->CopyButton, SIGNAL(clicked()), this, SLOT(slotCopyFunction()));
0336     connect(sb->RemoveButton, SIGNAL(clicked()), this, SLOT(slotRemoveFunction()));
0337     connect(sb->NewButton, SIGNAL(clicked()), this, SLOT(slotNew()));
0338     connect(sb->OpenButton, SIGNAL(clicked()), this, SLOT(slotOpen()));
0339     connect(sb->SaveButton, SIGNAL(clicked()), this, SLOT(slotSave()));
0340     connect(sb->SaveAsButton, SIGNAL(clicked()), this, SLOT(slotSaveAs()));
0341     connect(sb->AddButton, SIGNAL(clicked()), this, SLOT(slotAddFunction()));
0342     connect(sb->RunButton, SIGNAL(clicked()), this, SLOT(slotRunScript()));
0343 
0344     //Connections for Arg Widgets
0345     connect(argSetGeoLocation->FindCityButton, SIGNAL(clicked()), this, SLOT(slotFindCity()));
0346     connect(argLookToward->FindButton, SIGNAL(clicked()), this, SLOT(slotFindObject()));
0347     connect(argChangeViewOption->TreeButton, SIGNAL(clicked()), this, SLOT(slotShowOptions()));
0348     connect(argFindObject->FindButton, SIGNAL(clicked()), this, SLOT(slotFindObject()));
0349 
0350     connect(argLookToward->FocusEdit, SIGNAL(editTextChanged(QString)), this, SLOT(slotLookToward()));
0351     connect(argFindObject->NameEdit, SIGNAL(textChanged(QString)), this, SLOT(slotArgFindObject()));
0352     connect(argSetRaDec->RABox, SIGNAL(textChanged(QString)), this, SLOT(slotRa()));
0353     connect(argSetRaDec->DecBox, SIGNAL(textChanged(QString)), this, SLOT(slotDec()));
0354     connect(argSetAltAz->AltBox, SIGNAL(textChanged(QString)), this, SLOT(slotAlt()));
0355     connect(argSetAltAz->AzBox, SIGNAL(textChanged(QString)), this, SLOT(slotAz()));
0356     connect(argSetLocalTime->DateWidget, SIGNAL(dateChanged(QDate)), this, SLOT(slotChangeDate()));
0357     connect(argSetLocalTime->TimeBox, SIGNAL(timeChanged(QTime)), this, SLOT(slotChangeTime()));
0358     connect(argWaitFor->DelayBox, SIGNAL(valueChanged(int)), this, SLOT(slotWaitFor()));
0359     connect(argWaitForKey->WaitKeyEdit, SIGNAL(textChanged(QString)), this, SLOT(slotWaitForKey()));
0360     connect(argSetTracking->CheckTrack, SIGNAL(stateChanged(int)), this, SLOT(slotTracking()));
0361     connect(argChangeViewOption->OptionName, SIGNAL(activated(QString)), this, SLOT(slotViewOption()));
0362     connect(argChangeViewOption->OptionValue, SIGNAL(textChanged(QString)), this, SLOT(slotViewOption()));
0363     connect(argSetGeoLocation->CityName, SIGNAL(textChanged(QString)), this, SLOT(slotChangeCity()));
0364     connect(argSetGeoLocation->ProvinceName, SIGNAL(textChanged(QString)), this, SLOT(slotChangeProvince()));
0365     connect(argSetGeoLocation->CountryName, SIGNAL(textChanged(QString)), this, SLOT(slotChangeCountry()));
0366     connect(argTimeScale->TimeScale, SIGNAL(scaleChanged(float)), this, SLOT(slotTimeScale()));
0367     connect(argZoom->ZoomBox, SIGNAL(textChanged(QString)), this, SLOT(slotZoom()));
0368     connect(argExportImage->ExportFileName, SIGNAL(textChanged(QString)), this, SLOT(slotExportImage()));
0369     connect(argExportImage->ExportWidth, SIGNAL(valueChanged(int)), this, SLOT(slotExportImage()));
0370     connect(argExportImage->ExportHeight, SIGNAL(valueChanged(int)), this, SLOT(slotExportImage()));
0371     connect(argPrintImage->UsePrintDialog, SIGNAL(toggled(bool)), this, SLOT(slotPrintImage()));
0372     connect(argPrintImage->UseChartColors, SIGNAL(toggled(bool)), this, SLOT(slotPrintImage()));
0373     connect(argSetColor->ColorName, SIGNAL(activated(QString)), this, SLOT(slotChangeColorName()));
0374     connect(argSetColor->ColorValue, SIGNAL(changed(QColor)), this, SLOT(slotChangeColor()));
0375     connect(argLoadColorScheme->SchemeList, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(slotLoadColorScheme()));
0376 
0377     //disable some buttons
0378     sb->CopyButton->setEnabled(false);
0379     sb->AddButton->setEnabled(false);
0380     sb->RemoveButton->setEnabled(false);
0381     sb->UpButton->setEnabled(false);
0382     sb->DownButton->setEnabled(false);
0383     sb->SaveButton->setEnabled(false);
0384     sb->SaveAsButton->setEnabled(false);
0385     sb->RunButton->setEnabled(false);
0386 }
0387 
0388 ScriptBuilder::~ScriptBuilder()
0389 {
0390     while (!KStarsFunctionList.isEmpty())
0391         delete KStarsFunctionList.takeFirst();
0392 
0393     while (!SimClockFunctionList.isEmpty())
0394         delete SimClockFunctionList.takeFirst();
0395 
0396     while (!ScriptList.isEmpty())
0397         delete ScriptList.takeFirst();
0398 }
0399 
0400 void ScriptBuilder::initViewOptions()
0401 {
0402     otv->optionsList()->setRootIsDecorated(true);
0403     QStringList fields;
0404 
0405     //InfoBoxes
0406     opsGUI = new QTreeWidgetItem(otv->optionsList(), QStringList(i18n("InfoBoxes")));
0407     fields << "ShowInfoBoxes" << i18n("Toggle display of all InfoBoxes") << i18n("bool");
0408     new QTreeWidgetItem(opsGUI, fields);
0409     fields.clear();
0410     fields << "ShowTimeBox" << i18n("Toggle display of Time InfoBox") << i18n("bool");
0411     new QTreeWidgetItem(opsGUI, fields);
0412     fields.clear();
0413     fields << "ShowGeoBox" << i18n("Toggle display of Geographic InfoBox") << i18n("bool");
0414     new QTreeWidgetItem(opsGUI, fields);
0415     fields.clear();
0416     fields << "ShowFocusBox" << i18n("Toggle display of Focus InfoBox") << i18n("bool");
0417     new QTreeWidgetItem(opsGUI, fields);
0418     fields.clear();
0419     fields << "ShadeTimeBox" << i18n("(un)Shade Time InfoBox") << i18n("bool");
0420     new QTreeWidgetItem(opsGUI, fields);
0421     fields.clear();
0422     fields << "ShadeGeoBox" << i18n("(un)Shade Geographic InfoBox") << i18n("bool");
0423     new QTreeWidgetItem(opsGUI, fields);
0424     fields.clear();
0425     fields << "ShadeFocusBox" << i18n("(un)Shade Focus InfoBox") << i18n("bool");
0426     new QTreeWidgetItem(opsGUI, fields);
0427     fields.clear();
0428 
0429     argChangeViewOption->OptionName->addItem("ShowInfoBoxes");
0430     argChangeViewOption->OptionName->addItem("ShowTimeBox");
0431     argChangeViewOption->OptionName->addItem("ShowGeoBox");
0432     argChangeViewOption->OptionName->addItem("ShowFocusBox");
0433     argChangeViewOption->OptionName->addItem("ShadeTimeBox");
0434     argChangeViewOption->OptionName->addItem("ShadeGeoBox");
0435     argChangeViewOption->OptionName->addItem("ShadeFocusBox");
0436 
0437     //Toolbars
0438     opsToolbar = new QTreeWidgetItem(otv->optionsList(), QStringList(i18n("Toolbars")));
0439     fields << "ShowMainToolBar" << i18n("Toggle display of main toolbar") << i18n("bool");
0440     new QTreeWidgetItem(opsToolbar, fields);
0441     fields.clear();
0442     fields << "ShowViewToolBar" << i18n("Toggle display of view toolbar") << i18n("bool");
0443     new QTreeWidgetItem(opsToolbar, fields);
0444     fields.clear();
0445 
0446     argChangeViewOption->OptionName->addItem("ShowMainToolBar");
0447     argChangeViewOption->OptionName->addItem("ShowViewToolBar");
0448 
0449     //Show Objects
0450     opsShowObj = new QTreeWidgetItem(otv->optionsList(), QStringList(i18n("Show Objects")));
0451     fields << "ShowStars" << i18n("Toggle display of Stars") << i18n("bool");
0452     new QTreeWidgetItem(opsShowObj, fields);
0453     fields.clear();
0454     fields << "ShowDeepSky" << i18n("Toggle display of all deep-sky objects") << i18n("bool");
0455     new QTreeWidgetItem(opsShowObj, fields);
0456     fields.clear();
0457     new QTreeWidgetItem(opsShowObj, fields);
0458     fields.clear();
0459     new QTreeWidgetItem(opsShowObj, fields);
0460     fields.clear();
0461     fields << "ShowSolarSystem" << i18n("Toggle display of all solar system bodies") << i18n("bool");
0462     new QTreeWidgetItem(opsShowObj, fields);
0463     fields.clear();
0464     fields << "ShowSun" << i18n("Toggle display of Sun") << i18n("bool");
0465     new QTreeWidgetItem(opsShowObj, fields);
0466     fields.clear();
0467     fields << "ShowMoon" << i18n("Toggle display of Moon") << i18n("bool");
0468     new QTreeWidgetItem(opsShowObj, fields);
0469     fields.clear();
0470     fields << "ShowMercury" << i18n("Toggle display of Mercury") << i18n("bool");
0471     new QTreeWidgetItem(opsShowObj, fields);
0472     fields.clear();
0473     fields << "ShowVenus" << i18n("Toggle display of Venus") << i18n("bool");
0474     new QTreeWidgetItem(opsShowObj, fields);
0475     fields.clear();
0476     fields << "ShowMars" << i18n("Toggle display of Mars") << i18n("bool");
0477     new QTreeWidgetItem(opsShowObj, fields);
0478     fields.clear();
0479     fields << "ShowJupiter" << i18n("Toggle display of Jupiter") << i18n("bool");
0480     new QTreeWidgetItem(opsShowObj, fields);
0481     fields.clear();
0482     fields << "ShowSaturn" << i18n("Toggle display of Saturn") << i18n("bool");
0483     new QTreeWidgetItem(opsShowObj, fields);
0484     fields.clear();
0485     fields << "ShowUranus" << i18n("Toggle display of Uranus") << i18n("bool");
0486     new QTreeWidgetItem(opsShowObj, fields);
0487     fields.clear();
0488     fields << "ShowNeptune" << i18n("Toggle display of Neptune") << i18n("bool");
0489     new QTreeWidgetItem(opsShowObj, fields);
0490     //fields.clear();
0491     //fields << "ShowPluto" << i18n( "Toggle display of Pluto" ) << i18n( "bool" );
0492     //new QTreeWidgetItem( opsShowObj, fields );
0493     fields.clear();
0494     fields << "ShowAsteroids" << i18n("Toggle display of Asteroids") << i18n("bool");
0495     new QTreeWidgetItem(opsShowObj, fields);
0496     fields.clear();
0497     fields << "ShowComets" << i18n("Toggle display of Comets") << i18n("bool");
0498     new QTreeWidgetItem(opsShowObj, fields);
0499     fields.clear();
0500 
0501     argChangeViewOption->OptionName->addItem("ShowStars");
0502     argChangeViewOption->OptionName->addItem("ShowDeepSky");
0503     argChangeViewOption->OptionName->addItem("ShowSolarSystem");
0504     argChangeViewOption->OptionName->addItem("ShowSun");
0505     argChangeViewOption->OptionName->addItem("ShowMoon");
0506     argChangeViewOption->OptionName->addItem("ShowMercury");
0507     argChangeViewOption->OptionName->addItem("ShowVenus");
0508     argChangeViewOption->OptionName->addItem("ShowMars");
0509     argChangeViewOption->OptionName->addItem("ShowJupiter");
0510     argChangeViewOption->OptionName->addItem("ShowSaturn");
0511     argChangeViewOption->OptionName->addItem("ShowUranus");
0512     argChangeViewOption->OptionName->addItem("ShowNeptune");
0513     //argChangeViewOption->OptionName->addItem( "ShowPluto" );
0514     argChangeViewOption->OptionName->addItem("ShowAsteroids");
0515     argChangeViewOption->OptionName->addItem("ShowComets");
0516 
0517     opsShowOther = new QTreeWidgetItem(otv->optionsList(), QStringList(i18n("Show Other")));
0518     fields << "ShowCLines" << i18n("Toggle display of constellation lines") << i18n("bool");
0519     new QTreeWidgetItem(opsShowOther, fields);
0520     fields.clear();
0521     fields << "ShowCBounds" << i18n("Toggle display of constellation boundaries") << i18n("bool");
0522     new QTreeWidgetItem(opsShowOther, fields);
0523     fields.clear();
0524     fields << "ShowCNames" << i18n("Toggle display of constellation names") << i18n("bool");
0525     new QTreeWidgetItem(opsShowOther, fields);
0526     fields.clear();
0527     fields << "ShowMilkyWay" << i18n("Toggle display of Milky Way") << i18n("bool");
0528     new QTreeWidgetItem(opsShowOther, fields);
0529     fields.clear();
0530     fields << "ShowGrid" << i18n("Toggle display of the coordinate grid") << i18n("bool");
0531     new QTreeWidgetItem(opsShowOther, fields);
0532     fields.clear();
0533     fields << "ShowEquator" << i18n("Toggle display of the celestial equator") << i18n("bool");
0534     new QTreeWidgetItem(opsShowOther, fields);
0535     fields.clear();
0536     fields << "ShowEcliptic" << i18n("Toggle display of the ecliptic") << i18n("bool");
0537     new QTreeWidgetItem(opsShowOther, fields);
0538     fields.clear();
0539     fields << "ShowHorizon" << i18n("Toggle display of the horizon line") << i18n("bool");
0540     new QTreeWidgetItem(opsShowOther, fields);
0541     fields.clear();
0542     fields << "ShowGround" << i18n("Toggle display of the opaque ground") << i18n("bool");
0543     new QTreeWidgetItem(opsShowOther, fields);
0544     fields.clear();
0545     fields << "ShowStarNames" << i18n("Toggle display of star name labels") << i18n("bool");
0546     new QTreeWidgetItem(opsShowOther, fields);
0547     fields.clear();
0548     fields << "ShowStarMagnitudes" << i18n("Toggle display of star magnitude labels") << i18n("bool");
0549     new QTreeWidgetItem(opsShowOther, fields);
0550     fields.clear();
0551     fields << "ShowAsteroidNames" << i18n("Toggle display of asteroid name labels") << i18n("bool");
0552     new QTreeWidgetItem(opsShowOther, fields);
0553     fields.clear();
0554     fields << "ShowCometNames" << i18n("Toggle display of comet name labels") << i18n("bool");
0555     new QTreeWidgetItem(opsShowOther, fields);
0556     fields.clear();
0557     fields << "ShowPlanetNames" << i18n("Toggle display of planet name labels") << i18n("bool");
0558     new QTreeWidgetItem(opsShowOther, fields);
0559     fields.clear();
0560     fields << "ShowPlanetImages" << i18n("Toggle display of planet images") << i18n("bool");
0561     new QTreeWidgetItem(opsShowOther, fields);
0562     fields.clear();
0563 
0564     argChangeViewOption->OptionName->addItem("ShowCLines");
0565     argChangeViewOption->OptionName->addItem("ShowCBounds");
0566     argChangeViewOption->OptionName->addItem("ShowCNames");
0567     argChangeViewOption->OptionName->addItem("ShowMilkyWay");
0568     argChangeViewOption->OptionName->addItem("ShowGrid");
0569     argChangeViewOption->OptionName->addItem("ShowEquator");
0570     argChangeViewOption->OptionName->addItem("ShowEcliptic");
0571     argChangeViewOption->OptionName->addItem("ShowHorizon");
0572     argChangeViewOption->OptionName->addItem("ShowGround");
0573     argChangeViewOption->OptionName->addItem("ShowStarNames");
0574     argChangeViewOption->OptionName->addItem("ShowStarMagnitudes");
0575     argChangeViewOption->OptionName->addItem("ShowAsteroidNames");
0576     argChangeViewOption->OptionName->addItem("ShowCometNames");
0577     argChangeViewOption->OptionName->addItem("ShowPlanetNames");
0578     argChangeViewOption->OptionName->addItem("ShowPlanetImages");
0579 
0580     opsCName = new QTreeWidgetItem(otv->optionsList(), QStringList(i18n("Constellation Names")));
0581     fields << "UseLatinConstellNames" << i18n("Show Latin constellation names") << i18n("bool");
0582     new QTreeWidgetItem(opsCName, fields);
0583     fields.clear();
0584     fields << "UseLocalConstellNames" << i18n("Show constellation names in local language") << i18n("bool");
0585     new QTreeWidgetItem(opsCName, fields);
0586     fields.clear();
0587     fields << "UseAbbrevConstellNames" << i18n("Show IAU-standard constellation abbreviations") << i18n("bool");
0588     new QTreeWidgetItem(opsCName, fields);
0589     fields.clear();
0590 
0591     argChangeViewOption->OptionName->addItem("UseLatinConstellNames");
0592     argChangeViewOption->OptionName->addItem("UseLocalConstellNames");
0593     argChangeViewOption->OptionName->addItem("UseAbbrevConstellNames");
0594 
0595     opsHide = new QTreeWidgetItem(otv->optionsList(), QStringList(i18n("Hide Items")));
0596     fields << "HideOnSlew" << i18n("Toggle whether objects hidden while slewing display") << i18n("bool");
0597     new QTreeWidgetItem(opsHide, fields);
0598     fields.clear();
0599     fields << "SlewTimeScale" << i18n("Timestep threshold (in seconds) for hiding objects") << i18n("double");
0600     new QTreeWidgetItem(opsHide, fields);
0601     fields.clear();
0602     fields << "HideStars" << i18n("Hide faint stars while slewing?") << i18n("bool");
0603     new QTreeWidgetItem(opsHide, fields);
0604     fields.clear();
0605     fields << "HidePlanets" << i18n("Hide solar system bodies while slewing?") << i18n("bool");
0606     new QTreeWidgetItem(opsHide, fields);
0607     fields.clear();
0608     fields << "HideMilkyWay" << i18n("Hide Milky Way while slewing?") << i18n("bool");
0609     new QTreeWidgetItem(opsHide, fields);
0610     fields.clear();
0611     fields << "HideCNames" << i18n("Hide constellation names while slewing?") << i18n("bool");
0612     new QTreeWidgetItem(opsHide, fields);
0613     fields.clear();
0614     fields << "HideCLines" << i18n("Hide constellation lines while slewing?") << i18n("bool");
0615     new QTreeWidgetItem(opsHide, fields);
0616     fields.clear();
0617     fields << "HideCBounds" << i18n("Hide constellation boundaries while slewing?") << i18n("bool");
0618     new QTreeWidgetItem(opsHide, fields);
0619     fields.clear();
0620     fields << "HideGrid" << i18n("Hide coordinate grid while slewing?") << i18n("bool");
0621     new QTreeWidgetItem(opsHide, fields);
0622     fields.clear();
0623 
0624     argChangeViewOption->OptionName->addItem("HideOnSlew");
0625     argChangeViewOption->OptionName->addItem("SlewTimeScale");
0626     argChangeViewOption->OptionName->addItem("HideStars");
0627     argChangeViewOption->OptionName->addItem("HidePlanets");
0628     argChangeViewOption->OptionName->addItem("HideMilkyWay");
0629     argChangeViewOption->OptionName->addItem("HideCNames");
0630     argChangeViewOption->OptionName->addItem("HideCLines");
0631     argChangeViewOption->OptionName->addItem("HideCBounds");
0632     argChangeViewOption->OptionName->addItem("HideGrid");
0633 
0634     opsSkymap = new QTreeWidgetItem(otv->optionsList(), QStringList(i18n("Skymap Options")));
0635     fields << "UseAltAz" << i18n("Use Horizontal coordinates? (otherwise, use Equatorial)") << i18n("bool");
0636     new QTreeWidgetItem(opsSkymap, fields);
0637     fields.clear();
0638     fields << "ZoomFactor" << i18n("Set the Zoom Factor") << i18n("double");
0639     new QTreeWidgetItem(opsSkymap, fields);
0640     fields.clear();
0641     fields << "FOVName" << i18n("Select angular size for the FOV symbol (in arcmin)") << i18n("double");
0642     new QTreeWidgetItem(opsSkymap, fields);
0643     fields.clear();
0644     fields << "FOVShape" << i18n("Select shape for the FOV symbol (0=Square, 1=Circle, 2=Crosshairs, 4=Bullseye)")
0645            << i18n("int");
0646     new QTreeWidgetItem(opsSkymap, fields);
0647     fields.clear();
0648     fields << "FOVColor" << i18n("Select color for the FOV symbol") << i18n("string");
0649     new QTreeWidgetItem(opsSkymap, fields);
0650     fields.clear();
0651     fields << "UseAnimatedSlewing" << i18n("Use animated slewing? (otherwise, \"snap\" to new focus)") << i18n("bool");
0652     new QTreeWidgetItem(opsSkymap, fields);
0653     fields.clear();
0654     fields << "UseRefraction" << i18n("Correct for atmospheric refraction?") << i18n("bool");
0655     new QTreeWidgetItem(opsSkymap, fields);
0656     fields.clear();
0657     fields << "UseAutoLabel" << i18n("Automatically attach name label to centered object?") << i18n("bool");
0658     new QTreeWidgetItem(opsSkymap, fields);
0659     fields.clear();
0660     fields << "UseHoverLabel" << i18n("Attach temporary name label when hovering mouse over an object?")
0661            << i18n("bool");
0662     new QTreeWidgetItem(opsSkymap, fields);
0663     fields.clear();
0664     fields << "UseAutoTrail" << i18n("Automatically add trail to centered solar system body?") << i18n("bool");
0665     new QTreeWidgetItem(opsSkymap, fields);
0666     fields.clear();
0667     fields << "FadePlanetTrails" << i18n("Planet trails fade to sky color? (otherwise color is constant)")
0668            << i18n("bool");
0669     new QTreeWidgetItem(opsSkymap, fields);
0670     fields.clear();
0671 
0672     argChangeViewOption->OptionName->addItem("UseAltAz");
0673     argChangeViewOption->OptionName->addItem("ZoomFactor");
0674     argChangeViewOption->OptionName->addItem("FOVName");
0675     argChangeViewOption->OptionName->addItem("FOVSize");
0676     argChangeViewOption->OptionName->addItem("FOVShape");
0677     argChangeViewOption->OptionName->addItem("FOVColor");
0678     argChangeViewOption->OptionName->addItem("UseRefraction");
0679     argChangeViewOption->OptionName->addItem("UseAutoLabel");
0680     argChangeViewOption->OptionName->addItem("UseHoverLabel");
0681     argChangeViewOption->OptionName->addItem("UseAutoTrail");
0682     argChangeViewOption->OptionName->addItem("AnimateSlewing");
0683     argChangeViewOption->OptionName->addItem("FadePlanetTrails");
0684 
0685     opsLimit = new QTreeWidgetItem(otv->optionsList(), QStringList(i18n("Limits")));
0686     /*
0687     fields << "magLimitDrawStar" << i18n( "magnitude of faintest star drawn on map when zoomed in" ) << i18n( "double" );
0688     new QTreeWidgetItem( opsLimit, fields );
0689     fields.clear();
0690     fields << "magLimitDrawStarZoomOut" << i18n( "magnitude of faintest star drawn on map when zoomed out" ) << i18n( "double" );
0691     new QTreeWidgetItem( opsLimit, fields );
0692     fields.clear();
0693     */
0694 
0695     // TODO: We have disabled the following two features. Enable them when feasible...
0696     /*
0697     fields << "magLimitDrawDeepSky" << i18n( "magnitude of faintest nonstellar object drawn on map when zoomed in" ) << i18n( "double" );
0698     new QTreeWidgetItem( opsLimit, fields );
0699     fields.clear();
0700     fields << "magLimitDrawDeepSkyZoomOut" << i18n( "magnitude of faintest nonstellar object drawn on map when zoomed out" ) << i18n( "double" );
0701     new QTreeWidgetItem( opsLimit, fields );
0702     fields.clear();
0703     */
0704 
0705     //FIXME: This description is incorrect! Fix after strings freeze
0706     fields << "starLabelDensity" << i18n("magnitude of faintest star labeled on map") << i18n("double");
0707     new QTreeWidgetItem(opsLimit, fields);
0708     fields.clear();
0709     fields << "magLimitHideStar" << i18n("magnitude of brightest star hidden while slewing") << i18n("double");
0710     new QTreeWidgetItem(opsLimit, fields);
0711     fields.clear();
0712     fields << "magLimitAsteroid" << i18n("magnitude of faintest asteroid drawn on map") << i18n("double");
0713     new QTreeWidgetItem(opsLimit, fields);
0714     fields.clear();
0715     //FIXME: This description is incorrect! Fix after strings freeze
0716     fields << "asteroidLabelDensity" << i18n("magnitude of faintest asteroid labeled on map") << i18n("double");
0717     new QTreeWidgetItem(opsLimit, fields);
0718     fields.clear();
0719     fields << "maxRadCometName" << i18n("comets nearer to the Sun than this (in AU) are labeled on map")
0720            << i18n("double");
0721     new QTreeWidgetItem(opsLimit, fields);
0722     fields.clear();
0723 
0724     //    argChangeViewOption->OptionName->addItem( "magLimitDrawStar" );
0725     //    argChangeViewOption->OptionName->addItem( "magLimitDrawStarZoomOut" );
0726     argChangeViewOption->OptionName->addItem("magLimitDrawDeepSky");
0727     argChangeViewOption->OptionName->addItem("magLimitDrawDeepSkyZoomOut");
0728     argChangeViewOption->OptionName->addItem("starLabelDensity");
0729     argChangeViewOption->OptionName->addItem("magLimitHideStar");
0730     argChangeViewOption->OptionName->addItem("magLimitAsteroid");
0731     argChangeViewOption->OptionName->addItem("asteroidLabelDensity");
0732     argChangeViewOption->OptionName->addItem("maxRadCometName");
0733 
0734     //init the list of color names and values
0735     for (unsigned int i = 0; i < KStarsData::Instance()->colorScheme()->numberOfColors(); ++i)
0736     {
0737         argSetColor->ColorName->addItem(KStarsData::Instance()->colorScheme()->nameAt(i));
0738     }
0739 
0740     //init list of color scheme names
0741     argLoadColorScheme->SchemeList->addItem(i18nc("use default color scheme", "Default Colors"));
0742     argLoadColorScheme->SchemeList->addItem(i18nc("use 'star chart' color scheme", "Star Chart"));
0743     argLoadColorScheme->SchemeList->addItem(i18nc("use 'night vision' color scheme", "Night Vision"));
0744     argLoadColorScheme->SchemeList->addItem(i18nc("use 'moonless night' color scheme", "Moonless Night"));
0745 
0746     QFile file;
0747     QString line;
0748     //determine filename in local user KDE directory tree.
0749     file.setFileName(KSPaths::locate(QStandardPaths::AppLocalDataLocation, "colors.dat"));
0750     if (file.open(QIODevice::ReadOnly))
0751     {
0752         QTextStream stream(&file);
0753 
0754         while (!stream.atEnd())
0755         {
0756             line = stream.readLine();
0757             argLoadColorScheme->SchemeList->addItem(line.left(line.indexOf(':')));
0758         }
0759         file.close();
0760     }
0761 }
0762 
0763 //Slots defined in ScriptBuilderUI
0764 void ScriptBuilder::slotNew()
0765 {
0766     saveWarning();
0767     if (!UnsavedChanges)
0768     {
0769         ScriptList.clear();
0770         sb->ScriptListBox->clear();
0771         sb->ArgStack->setCurrentWidget(argBlank);
0772 
0773         sb->CopyButton->setEnabled(false);
0774         sb->RemoveButton->setEnabled(false);
0775         sb->RunButton->setEnabled(false);
0776         sb->SaveAsButton->setEnabled(false);
0777 
0778         currentFileURL.clear();
0779         currentScriptName.clear();
0780     }
0781 }
0782 
0783 void ScriptBuilder::slotOpen()
0784 {
0785     saveWarning();
0786 
0787     QString fname;
0788     QTemporaryFile tmpfile;
0789     tmpfile.open();
0790 
0791     if (!UnsavedChanges)
0792     {
0793         currentFileURL = QFileDialog::getOpenFileUrl(
0794                              KStars::Instance(), QString(), QUrl(currentDir),
0795                              "*.kstars|" + i18nc("Filter by file type: KStars Scripts.", "KStars Scripts (*.kstars)"));
0796 
0797         if (currentFileURL.isValid())
0798         {
0799             currentDir = currentFileURL.toLocalFile();
0800 
0801             ScriptList.clear();
0802             sb->ScriptListBox->clear();
0803             sb->ArgStack->setCurrentWidget(argBlank);
0804 
0805             if (currentFileURL.isLocalFile())
0806             {
0807                 fname = currentFileURL.toLocalFile();
0808             }
0809             else
0810             {
0811                 fname = tmpfile.fileName();
0812                 if (KIO::copy(currentFileURL, QUrl(fname))->exec() == false)
0813                     //if ( ! KIO::NetAccess::download( currentFileURL, fname, (QWidget*) 0 ) )
0814                     KSNotification::sorry(i18n("Could not download remote file."), i18n("Download Error"));
0815             }
0816 
0817             QFile f(fname);
0818             if (!f.open(QIODevice::ReadOnly))
0819             {
0820                 KSNotification::sorry(i18n("Could not open file %1.", f.fileName()), i18n("Could Not Open File"));
0821                 currentFileURL.clear();
0822                 return;
0823             }
0824 
0825             QTextStream istream(&f);
0826             readScript(istream);
0827 
0828             f.close();
0829         }
0830         else if (!currentFileURL.url().isEmpty())
0831         {
0832             KSNotification::sorry(i18n("Invalid URL: %1", currentFileURL.url()), i18n("Invalid URL"));
0833             currentFileURL.clear();
0834         }
0835     }
0836 }
0837 
0838 void ScriptBuilder::slotSave()
0839 {
0840     QString fname;
0841     QTemporaryFile tmpfile;
0842     tmpfile.open();
0843 
0844     if (currentScriptName.isEmpty())
0845     {
0846         //Get Script Name and Author info
0847         if (snd->exec() == QDialog::Accepted)
0848         {
0849             currentScriptName = snd->scriptName();
0850             currentAuthor     = snd->authorName();
0851         }
0852         else
0853         {
0854             return;
0855         }
0856     }
0857 
0858     bool newFilename = false;
0859     if (currentFileURL.isEmpty())
0860     {
0861         currentFileURL = QFileDialog::getSaveFileUrl(
0862                              KStars::Instance(), QString(), QUrl(currentDir),
0863                              "*.kstars|" + i18nc("Filter by file type: KStars Scripts.", "KStars Scripts (*.kstars)"));
0864         newFilename = true;
0865     }
0866 
0867     if (currentFileURL.isValid())
0868     {
0869         currentDir = currentFileURL.toLocalFile();
0870 
0871         if (currentFileURL.isLocalFile())
0872         {
0873             fname = currentFileURL.toLocalFile();
0874 
0875             //Warn user if file exists
0876             if (newFilename == true && QFile::exists(currentFileURL.toLocalFile()))
0877             {
0878                 int r = KMessageBox::warningContinueCancel(static_cast<QWidget *>(parent()),
0879                         i18n("A file named \"%1\" already exists. "
0880                              "Overwrite it?",
0881                              currentFileURL.fileName()),
0882                         i18n("Overwrite File?"), KStandardGuiItem::overwrite());
0883 
0884                 if (r == KMessageBox::Cancel)
0885                     return;
0886             }
0887         }
0888         else
0889         {
0890             fname = tmpfile.fileName();
0891         }
0892 
0893         if (fname.right(7).toLower() != ".kstars")
0894             fname += ".kstars";
0895 
0896         QFile f(fname);
0897         if (!f.open(QIODevice::WriteOnly))
0898         {
0899             QString message = i18n("Could not open file %1.", f.fileName());
0900             KSNotification::sorry(message, i18n("Could Not Open File"));
0901             currentFileURL.clear();
0902             return;
0903         }
0904 
0905         QTextStream ostream(&f);
0906         writeScript(ostream);
0907         f.close();
0908 
0909 #ifndef _WIN32
0910         //set rwx for owner, rx for group, rx for other
0911         chmod(fname.toLatin1(), S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
0912 #endif
0913 
0914         if (tmpfile.fileName() == fname)
0915         {
0916             //need to upload to remote location
0917             //if ( ! KIO::NetAccess::upload( tmpfile.fileName(), currentFileURL, (QWidget*) 0 ) )
0918             if (KIO::storedHttpPost(&tmpfile, currentFileURL)->exec() == false)
0919             {
0920                 QString message = i18n("Could not upload image to remote location: %1", currentFileURL.url());
0921                 KSNotification::sorry(message, i18n("Could not upload file"));
0922             }
0923         }
0924 
0925         setUnsavedChanges(false);
0926     }
0927     else
0928     {
0929         QString message = i18n("Invalid URL: %1", currentFileURL.url());
0930         KSNotification::sorry(message, i18n("Invalid URL"));
0931         currentFileURL.clear();
0932     }
0933 }
0934 
0935 void ScriptBuilder::slotSaveAs()
0936 {
0937     currentFileURL.clear();
0938     currentScriptName.clear();
0939     slotSave();
0940 }
0941 
0942 void ScriptBuilder::saveWarning()
0943 {
0944     if (UnsavedChanges)
0945     {
0946         QString caption = i18n("Save Changes to Script?");
0947         QString message = i18n("The current script has unsaved changes.  Would you like to save before closing it?");
0948         int ans =
0949             KMessageBox::warningYesNoCancel(nullptr, message, caption, KStandardGuiItem::save(), KStandardGuiItem::discard());
0950         if (ans == KMessageBox::Yes)
0951         {
0952             slotSave();
0953             setUnsavedChanges(false);
0954         }
0955         else if (ans == KMessageBox::No)
0956         {
0957             setUnsavedChanges(false);
0958         }
0959 
0960         //Do nothing if 'cancel' selected
0961     }
0962 }
0963 
0964 void ScriptBuilder::slotRunScript()
0965 {
0966     //hide window while script runs
0967     // If this is uncommented, the program hangs before the script is executed.  Why?
0968     //  hide();
0969 
0970     //Save current script to a temporary file, then execute that file.
0971     //For some reason, I can't use KTempFile here!  If I do, then the temporary script
0972     //is not executable.  Bizarre...
0973     //KTempFile tmpfile;
0974     //QString fname = tmpfile.name();
0975     QString fname = QDir::tempPath() + QDir::separator() + "kstars-tempscript";
0976 
0977     QFile f(fname);
0978     if (f.exists())
0979         f.remove();
0980     if (!f.open(QIODevice::WriteOnly))
0981     {
0982         QString message = i18n("Could not open file %1.", f.fileName());
0983         KSNotification::sorry(message, i18n("Could Not Open File"));
0984         currentFileURL.clear();
0985         return;
0986     }
0987 
0988     QTextStream ostream(&f);
0989     writeScript(ostream);
0990     f.close();
0991 
0992 #ifndef _WIN32
0993     //set rwx for owner, rx for group, rx for other
0994     chmod(QFile::encodeName(f.fileName()), S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
0995 #endif
0996 
0997     QProcess p;
0998 #ifdef Q_OS_OSX
0999     QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
1000     QString path            = env.value("PATH", "");
1001     env.insert("PATH", "/usr/local/bin:" + QCoreApplication::applicationDirPath() + ':' + path);
1002     p.setProcessEnvironment(env);
1003 #endif
1004     QStringList arguments;
1005     p.start(f.fileName(), arguments);
1006 
1007     if (!p.waitForStarted())
1008         qDebug() << Q_FUNC_INFO << "Process did not start.";
1009 
1010     while (!p.waitForFinished(10))
1011     {
1012         qApp->processEvents(); //otherwise tempfile may get deleted before script completes.
1013         if (p.state() != QProcess::Running)
1014             break;
1015     }
1016     //delete temp file
1017     if (f.exists())
1018         f.remove();
1019 
1020     //uncomment if 'hide()' is uncommented...
1021     //  show();
1022 }
1023 
1024 /*
1025   This can't work anymore and is also not portable in any way :(
1026 */
1027 void ScriptBuilder::writeScript(QTextStream &ostream)
1028 {
1029     // FIXME Without --print-reply, the dbus-send doesn't do anything, why??
1030     QString dbus_call    = "dbus-send --dest=org.kde.kstars --print-reply ";
1031     QString main_method  = "/KStars org.kde.kstars.";
1032     QString clock_method = "/KStars/SimClock org.kde.kstars.SimClock.";
1033 
1034     //Write script header
1035     ostream << "#!/bin/bash\n";
1036     ostream << "#KStars DBus script: " << currentScriptName << '\n';
1037     ostream << "#by " << currentAuthor << '\n';
1038     ostream << "#last modified: " << KStarsDateTime::currentDateTime().toString(Qt::ISODate) << '\n';
1039     ostream << "#\n";
1040 
1041     foreach (ScriptFunction *sf, ScriptList)
1042     {
1043         if (!sf->valid())
1044             continue;
1045 
1046         if (sf->isClockFunction())
1047         {
1048             ostream << dbus_call << clock_method << sf->scriptLine() << '\n';
1049         }
1050         else
1051         {
1052             ostream << dbus_call << main_method << sf->scriptLine() << '\n';
1053         }
1054     }
1055 
1056     //Write script footer
1057     ostream << "##\n";
1058     ostream.flush();
1059 }
1060 
1061 void ScriptBuilder::readScript(QTextStream &istream)
1062 {
1063     QString line;
1064     QString service_name = "org.kde.kstars.";
1065     QString fn_name;
1066 
1067     while (!istream.atEnd())
1068     {
1069         line = istream.readLine();
1070 
1071         //look for name of script
1072         if (line.contains("#KStars DBus script: "))
1073             currentScriptName = line.mid(21).trimmed();
1074 
1075         //look for author of scriptbuilder
1076         if (line.contains("#by "))
1077             currentAuthor = line.mid(4).trimmed();
1078 
1079         //Actual script functions
1080         if (line.left(4) == "dbus")
1081         {
1082             //is ClockFunction?
1083             if (line.contains("SimClock"))
1084             {
1085                 service_name += "SimClock.";
1086             }
1087 
1088             //remove leading dbus prefix
1089             line = line.mid(line.lastIndexOf(service_name) + service_name.count());
1090 
1091             fn_name = line.left(line.indexOf(' '));
1092 
1093             line = line.mid(line.indexOf(' ') + 1);
1094 
1095             //construct a stringlist that is fcn name and its arg name/value pairs
1096             QStringList fn;
1097 
1098             // If the function lacks any arguments, do not attempt to split
1099             //            if (fn_name != line)
1100             //                fn = line.split(' ');
1101 
1102             if (parseFunction(fn_name, line))
1103             {
1104                 sb->ScriptListBox->addItem(ScriptList.last()->name());
1105                 // Initially, any read script is valid!
1106                 ScriptList.last()->setValid(true);
1107             }
1108             else
1109                 qWarning() << i18n("Could not parse script.  Line was: %1", line);
1110 
1111         } // end if left(4) == "dcop"
1112     }     // end while !atEnd()
1113 
1114     //Select first item in sb->ScriptListBox
1115     if (sb->ScriptListBox->count())
1116     {
1117         sb->ScriptListBox->setCurrentItem(nullptr);
1118         slotArgWidget();
1119     }
1120 }
1121 
1122 bool ScriptBuilder::parseFunction(const QString &fn_name, const QString &fn_args)
1123 {
1124     // clean up the string list first if needed
1125     // We need to perform this in case we havea quoted string "NGC 3000" because this will counted
1126     // as two arguments, and it should be counted as one.
1127     //    bool foundQuote(false), quoteProcessed(false);
1128     //    QString cur, arg;
1129     //    QStringList::iterator it;
1130 
1131     //    for (it = fn.begin(); it != fn.end(); ++it)
1132     //    {
1133     //        cur = (*it);
1134 
1135     //        cur = cur.mid(cur.indexOf(":") + 1).remove('\'');
1136 
1137     //        (*it) = cur;
1138 
1139     //        if (cur.startsWith('\"'))
1140     //        {
1141     //            arg += cur.rightRef(cur.length() - 1);
1142     //            arg += ' ';
1143     //            foundQuote     = true;
1144     //            quoteProcessed = true;
1145     //        }
1146     //        else if (cur.endsWith('\"'))
1147     //        {
1148     //            arg += cur.leftRef(cur.length() - 1);
1149     //            arg += '\'';
1150     //            foundQuote = false;
1151     //        }
1152     //        else if (foundQuote)
1153     //        {
1154     //            arg += cur;
1155     //            arg += ' ';
1156     //        }
1157     //        else
1158     //        {
1159     //            arg += cur;
1160     //            arg += '\'';
1161     //        }
1162     //    }
1163 
1164     //    if (quoteProcessed)
1165     //        fn = arg.split(' ', QString::SkipEmptyParts);
1166 
1167     QRegularExpression re("(?<=:)[^:\\s]*");
1168     QRegularExpressionMatchIterator i = re.globalMatch(fn_args);
1169     QStringList fn;
1170     while (i.hasNext())
1171     {
1172         QRegularExpressionMatch match = i.next();
1173         fn << match.captured(0).remove("\"");
1174     };
1175 
1176     //loop over known functions to find a name match
1177     for (auto &sf : KStarsFunctionList)
1178     {
1179         if (fn_name == sf->name())
1180         {
1181             //            if (fn_name == "setGeoLocation")
1182             //            {
1183             //                ScriptList.append(new ScriptFunction(sf));
1184             //                ScriptList.last()->setArg(0, fn[0]);
1185             //                ScriptList.last()->setArg(1, fn[1]);
1186             //                ScriptList.last()->setArg(2, fn[2]);
1187             //            }
1188             //            else if (fn.count() != sf->numArgs())
1189             //                return false;
1190 
1191             ScriptList.append(new ScriptFunction(sf));
1192 
1193             for (int i = 0; i < sf->numArgs(); ++i)
1194                 ScriptList.last()->setArg(i, fn[i]);
1195 
1196             return true;
1197         }
1198 
1199         foreach (ScriptFunction *sf, SimClockFunctionList)
1200         {
1201             if (fn_name == sf->name())
1202             {
1203                 if (fn.count() != sf->numArgs())
1204                     return false;
1205 
1206                 ScriptList.append(new ScriptFunction(sf));
1207 
1208                 for (int i = 0; i < sf->numArgs(); ++i)
1209                     ScriptList.last()->setArg(i, fn[i]);
1210 
1211                 return true;
1212             }
1213         }
1214     }
1215 
1216     //if we get here, no function-name match was found
1217     return false;
1218 }
1219 
1220 void ScriptBuilder::setUnsavedChanges(bool b)
1221 {
1222     if (checkForChanges)
1223     {
1224         UnsavedChanges = b;
1225         sb->SaveButton->setEnabled(b);
1226     }
1227 }
1228 
1229 void ScriptBuilder::slotCopyFunction()
1230 {
1231     if (!UnsavedChanges)
1232         setUnsavedChanges(true);
1233 
1234     int Pos = sb->ScriptListBox->currentRow() + 1;
1235     ScriptList.insert(Pos, new ScriptFunction(ScriptList[Pos - 1]));
1236     //copy ArgVals
1237     for (int i = 0; i < ScriptList[Pos - 1]->numArgs(); ++i)
1238         ScriptList[Pos]->setArg(i, ScriptList[Pos - 1]->argVal(i));
1239 
1240     sb->ScriptListBox->insertItem(Pos, ScriptList[Pos]->name());
1241     //sb->ScriptListBox->setSelected( Pos, true );
1242     sb->ScriptListBox->setCurrentRow(Pos);
1243     slotArgWidget();
1244 }
1245 
1246 void ScriptBuilder::slotRemoveFunction()
1247 {
1248     setUnsavedChanges(true);
1249 
1250     int Pos = sb->ScriptListBox->currentRow();
1251     ScriptList.removeAt(Pos);
1252     sb->ScriptListBox->takeItem(Pos);
1253     if (sb->ScriptListBox->count() == 0)
1254     {
1255         sb->ArgStack->setCurrentWidget(argBlank);
1256         sb->CopyButton->setEnabled(false);
1257         sb->RemoveButton->setEnabled(false);
1258         sb->RunButton->setEnabled(false);
1259         sb->SaveAsButton->setEnabled(false);
1260     }
1261     else
1262     {
1263         //sb->ScriptListBox->setSelected( Pos, true );
1264         if (Pos == sb->ScriptListBox->count())
1265         {
1266             Pos = Pos - 1;
1267         }
1268         sb->ScriptListBox->setCurrentRow(Pos);
1269     }
1270     slotArgWidget();
1271 }
1272 
1273 void ScriptBuilder::slotAddFunction()
1274 {
1275     ScriptFunction *found        = nullptr;
1276     QTreeWidgetItem *currentItem = sb->FunctionTree->currentItem();
1277 
1278     if (currentItem == nullptr || currentItem->parent() == nullptr)
1279         return;
1280 
1281     for (auto &sc : KStarsFunctionList)
1282     {
1283         if (sc->prototype() == currentItem->text(0))
1284         {
1285             found = sc;
1286             break;
1287         }
1288     }
1289 
1290     for (auto &sc : SimClockFunctionList)
1291     {
1292         if (sc->prototype() == currentItem->text(0))
1293         {
1294             found = sc;
1295             break;
1296         }
1297     }
1298 
1299     if (found == nullptr)
1300         return;
1301 
1302     setUnsavedChanges(true);
1303 
1304     int Pos = sb->ScriptListBox->currentRow() + 1;
1305 
1306     ScriptList.insert(Pos, new ScriptFunction(found));
1307     sb->ScriptListBox->insertItem(Pos, ScriptList[Pos]->name());
1308     sb->ScriptListBox->setCurrentRow(Pos);
1309     slotArgWidget();
1310 }
1311 
1312 void ScriptBuilder::slotMoveFunctionUp()
1313 {
1314     if (sb->ScriptListBox->currentRow() > 0)
1315     {
1316         setUnsavedChanges(true);
1317 
1318         //QString t = sb->ScriptListBox->currentItem()->text();
1319         QString t      = sb->ScriptListBox->currentItem()->text();
1320         unsigned int n = sb->ScriptListBox->currentRow();
1321 
1322         ScriptFunction *tmp = ScriptList.takeAt(n);
1323         ScriptList.insert(n - 1, tmp);
1324 
1325         sb->ScriptListBox->takeItem(n);
1326         sb->ScriptListBox->insertItem(n - 1, t);
1327         sb->ScriptListBox->setCurrentRow(n - 1);
1328         slotArgWidget();
1329     }
1330 }
1331 
1332 void ScriptBuilder::slotMoveFunctionDown()
1333 {
1334     if (sb->ScriptListBox->currentRow() > -1 && sb->ScriptListBox->currentRow() < ((int)sb->ScriptListBox->count()) - 1)
1335     {
1336         setUnsavedChanges(true);
1337 
1338         QString t      = sb->ScriptListBox->currentItem()->text();
1339         unsigned int n = sb->ScriptListBox->currentRow();
1340 
1341         ScriptFunction *tmp = ScriptList.takeAt(n);
1342         ScriptList.insert(n + 1, tmp);
1343 
1344         sb->ScriptListBox->takeItem(n);
1345         sb->ScriptListBox->insertItem(n + 1, t);
1346         sb->ScriptListBox->setCurrentRow(n + 1);
1347         slotArgWidget();
1348     }
1349 }
1350 
1351 void ScriptBuilder::slotArgWidget()
1352 {
1353     //First, setEnabled on buttons that act on the selected script function
1354     if (sb->ScriptListBox->currentRow() == -1) //no selection
1355     {
1356         sb->CopyButton->setEnabled(false);
1357         sb->RemoveButton->setEnabled(false);
1358         sb->UpButton->setEnabled(false);
1359         sb->DownButton->setEnabled(false);
1360     }
1361     else if (sb->ScriptListBox->count() == 1) //only one item, so disable up/down buttons
1362     {
1363         sb->CopyButton->setEnabled(true);
1364         sb->RemoveButton->setEnabled(true);
1365         sb->UpButton->setEnabled(false);
1366         sb->DownButton->setEnabled(false);
1367     }
1368     else if (sb->ScriptListBox->currentRow() == 0) //first item selected
1369     {
1370         sb->CopyButton->setEnabled(true);
1371         sb->RemoveButton->setEnabled(true);
1372         sb->UpButton->setEnabled(false);
1373         sb->DownButton->setEnabled(true);
1374     }
1375     else if (sb->ScriptListBox->currentRow() == ((int)sb->ScriptListBox->count()) - 1) //last item selected
1376     {
1377         sb->CopyButton->setEnabled(true);
1378         sb->RemoveButton->setEnabled(true);
1379         sb->UpButton->setEnabled(true);
1380         sb->DownButton->setEnabled(false);
1381     }
1382     else //other item selected
1383     {
1384         sb->CopyButton->setEnabled(true);
1385         sb->RemoveButton->setEnabled(true);
1386         sb->UpButton->setEnabled(true);
1387         sb->DownButton->setEnabled(true);
1388     }
1389 
1390     //RunButton and SaveAs button enabled when script not empty.
1391     if (sb->ScriptListBox->count())
1392     {
1393         sb->RunButton->setEnabled(true);
1394         sb->SaveAsButton->setEnabled(true);
1395     }
1396     else
1397     {
1398         sb->RunButton->setEnabled(false);
1399         sb->SaveAsButton->setEnabled(false);
1400         setUnsavedChanges(false);
1401     }
1402 
1403     //Display the function's arguments widget
1404     if (sb->ScriptListBox->currentRow() > -1 && sb->ScriptListBox->currentRow() < ((int)sb->ScriptListBox->count()))
1405     {
1406         unsigned int n     = sb->ScriptListBox->currentRow();
1407         ScriptFunction *sf = ScriptList.at(n);
1408 
1409         checkForChanges = false; //Don't signal unsaved changes
1410 
1411         if (sf->name() == "lookTowards")
1412         {
1413             sb->ArgStack->setCurrentWidget(argLookToward);
1414             QString s = sf->argVal(0);
1415             argLookToward->FocusEdit->setEditText(s);
1416         }
1417         else if (sf->name() == "addLabel" || sf->name() == "removeLabel" || sf->name() == "addTrail" ||
1418                  sf->name() == "removeTrail")
1419         {
1420             sb->ArgStack->setCurrentWidget(argFindObject);
1421             QString s = sf->argVal(0);
1422             argFindObject->NameEdit->setText(s);
1423         }
1424         else if (sf->name() == "setRaDec")
1425         {
1426             bool ok(false);
1427             double r(0.0), d(0.0);
1428             dms ra(0.0);
1429 
1430             sb->ArgStack->setCurrentWidget(argSetRaDec);
1431 
1432             ok = !sf->argVal(0).isEmpty();
1433             if (ok)
1434                 r = sf->argVal(0).toDouble(&ok);
1435             else
1436                 argSetRaDec->RABox->clear();
1437             if (ok)
1438             {
1439                 ra.setH(r);
1440                 argSetRaDec->RABox->show(ra);
1441             }
1442 
1443             ok = !sf->argVal(1).isEmpty();
1444             if (ok)
1445                 d = sf->argVal(1).toDouble(&ok);
1446             else
1447                 argSetRaDec->DecBox->clear();
1448             if (ok)
1449                 argSetRaDec->DecBox->show(dms(d));
1450         }
1451         else if (sf->name() == "setAltAz")
1452         {
1453             bool ok(false);
1454             double x(0.0), y(0.0);
1455 
1456             sb->ArgStack->setCurrentWidget(argSetAltAz);
1457 
1458             ok = !sf->argVal(0).isEmpty();
1459             if (ok)
1460                 y = sf->argVal(0).toDouble(&ok);
1461             else
1462                 argSetAltAz->AzBox->clear();
1463             if (ok)
1464                 argSetAltAz->AltBox->show(dms(y));
1465             else
1466                 argSetAltAz->AltBox->clear();
1467 
1468             ok = !sf->argVal(1).isEmpty();
1469             x  = sf->argVal(1).toDouble(&ok);
1470             if (ok)
1471                 argSetAltAz->AzBox->show(dms(x));
1472         }
1473         else if (sf->name() == "zoomIn")
1474         {
1475             sb->ArgStack->setCurrentWidget(argBlank);
1476             //no Args
1477         }
1478         else if (sf->name() == "zoomOut")
1479         {
1480             sb->ArgStack->setCurrentWidget(argBlank);
1481             //no Args
1482         }
1483         else if (sf->name() == "defaultZoom")
1484         {
1485             sb->ArgStack->setCurrentWidget(argBlank);
1486             //no Args
1487         }
1488         else if (sf->name() == "zoom")
1489         {
1490             sb->ArgStack->setCurrentWidget(argZoom);
1491             bool ok(false);
1492             /*double z = */ sf->argVal(0).toDouble(&ok);
1493             if (ok)
1494                 argZoom->ZoomBox->setText(sf->argVal(0));
1495             else
1496                 argZoom->ZoomBox->setText("2000.");
1497         }
1498         else if (sf->name() == "exportImage")
1499         {
1500             sb->ArgStack->setCurrentWidget(argExportImage);
1501             argExportImage->ExportFileName->setUrl(QUrl::fromUserInput(sf->argVal(0)));
1502             bool ok(false);
1503             int w = 0, h = 0;
1504             w = sf->argVal(1).toInt(&ok);
1505             if (ok)
1506                 h = sf->argVal(2).toInt(&ok);
1507             if (ok)
1508             {
1509                 argExportImage->ExportWidth->setValue(w);
1510                 argExportImage->ExportHeight->setValue(h);
1511             }
1512             else
1513             {
1514                 argExportImage->ExportWidth->setValue(SkyMap::Instance()->width());
1515                 argExportImage->ExportHeight->setValue(SkyMap::Instance()->height());
1516             }
1517         }
1518         else if (sf->name() == "printImage")
1519         {
1520             if (sf->argVal(0) == i18n("true"))
1521                 argPrintImage->UsePrintDialog->setChecked(true);
1522             else
1523                 argPrintImage->UsePrintDialog->setChecked(false);
1524             if (sf->argVal(1) == i18n("true"))
1525                 argPrintImage->UseChartColors->setChecked(true);
1526             else
1527                 argPrintImage->UseChartColors->setChecked(false);
1528         }
1529         else if (sf->name() == "setLocalTime")
1530         {
1531             sb->ArgStack->setCurrentWidget(argSetLocalTime);
1532             bool ok(false);
1533             int year = 0, month = 0, day = 0, hour = 0, min = 0, sec = 0;
1534 
1535             year = sf->argVal(0).toInt(&ok);
1536             if (ok)
1537                 month = sf->argVal(1).toInt(&ok);
1538             if (ok)
1539                 day = sf->argVal(2).toInt(&ok);
1540             if (ok)
1541                 argSetLocalTime->DateWidget->setDate(QDate(year, month, day));
1542             else
1543                 argSetLocalTime->DateWidget->setDate(QDate::currentDate());
1544 
1545             hour = sf->argVal(3).toInt(&ok);
1546             if (sf->argVal(3).isEmpty())
1547                 ok = false;
1548             if (ok)
1549                 min = sf->argVal(4).toInt(&ok);
1550             if (ok)
1551                 sec = sf->argVal(5).toInt(&ok);
1552             if (ok)
1553                 argSetLocalTime->TimeBox->setTime(QTime(hour, min, sec));
1554             else
1555                 argSetLocalTime->TimeBox->setTime(QTime(QTime::currentTime()));
1556         }
1557         else if (sf->name() == "waitFor")
1558         {
1559             sb->ArgStack->setCurrentWidget(argWaitFor);
1560             bool ok(false);
1561             int sec = sf->argVal(0).toInt(&ok);
1562             if (ok)
1563                 argWaitFor->DelayBox->setValue(sec);
1564             else
1565                 argWaitFor->DelayBox->setValue(0);
1566         }
1567         else if (sf->name() == "waitForKey")
1568         {
1569             sb->ArgStack->setCurrentWidget(argWaitForKey);
1570             if (sf->argVal(0).length() == 1 || sf->argVal(0).toLower() == "space")
1571                 argWaitForKey->WaitKeyEdit->setText(sf->argVal(0));
1572             else
1573                 argWaitForKey->WaitKeyEdit->setText(QString());
1574         }
1575         else if (sf->name() == "setTracking")
1576         {
1577             sb->ArgStack->setCurrentWidget(argSetTracking);
1578             if (sf->argVal(0) == i18n("true"))
1579                 argSetTracking->CheckTrack->setChecked(true);
1580             else
1581                 argSetTracking->CheckTrack->setChecked(false);
1582         }
1583         else if (sf->name() == "changeViewOption")
1584         {
1585             sb->ArgStack->setCurrentWidget(argChangeViewOption);
1586             argChangeViewOption->OptionName->setCurrentIndex(argChangeViewOption->OptionName->findText(sf->argVal(0)));
1587             argChangeViewOption->OptionValue->setText(sf->argVal(1));
1588         }
1589         else if (sf->name() == "setGeoLocation")
1590         {
1591             sb->ArgStack->setCurrentWidget(argSetGeoLocation);
1592             argSetGeoLocation->CityName->setText(sf->argVal(0));
1593             argSetGeoLocation->ProvinceName->setText(sf->argVal(1));
1594             argSetGeoLocation->CountryName->setText(sf->argVal(2));
1595         }
1596         else if (sf->name() == "setColor")
1597         {
1598             sb->ArgStack->setCurrentWidget(argSetColor);
1599             if (sf->argVal(0).isEmpty())
1600                 sf->setArg(0, "SkyColor"); //initialize default value
1601             argSetColor->ColorName->setCurrentIndex(
1602                 argSetColor->ColorName->findText(KStarsData::Instance()->colorScheme()->nameFromKey(sf->argVal(0))));
1603             argSetColor->ColorValue->setColor(QColor(sf->argVal(1).remove('\\')));
1604         }
1605         else if (sf->name() == "loadColorScheme")
1606         {
1607             sb->ArgStack->setCurrentWidget(argLoadColorScheme);
1608             argLoadColorScheme->SchemeList->setCurrentItem(
1609                 argLoadColorScheme->SchemeList->findItems(sf->argVal(0).remove('\"'), Qt::MatchExactly).at(0));
1610         }
1611         else if (sf->name() == "stop")
1612         {
1613             sb->ArgStack->setCurrentWidget(argBlank);
1614             //no Args
1615         }
1616         else if (sf->name() == "start")
1617         {
1618             sb->ArgStack->setCurrentWidget(argBlank);
1619             //no Args
1620         }
1621         else if (sf->name() == "setClockScale")
1622         {
1623             sb->ArgStack->setCurrentWidget(argTimeScale);
1624             bool ok(false);
1625             double ts = sf->argVal(0).toDouble(&ok);
1626             if (ok)
1627                 argTimeScale->TimeScale->tsbox()->changeScale(float(ts));
1628             else
1629                 argTimeScale->TimeScale->tsbox()->changeScale(0.0);
1630         }
1631 
1632         checkForChanges = true; //signal unsaved changes if the argument widgets are changed
1633     }
1634 }
1635 
1636 void ScriptBuilder::slotShowDoc()
1637 {
1638     ScriptFunction *found        = nullptr;
1639     QTreeWidgetItem *currentItem = sb->FunctionTree->currentItem();
1640 
1641     if (currentItem == nullptr || currentItem->parent() == nullptr)
1642         return;
1643 
1644     for (auto &sc : KStarsFunctionList)
1645     {
1646         if (sc->prototype() == currentItem->text(0))
1647         {
1648             found = sc;
1649             break;
1650         }
1651     }
1652 
1653     for (auto &sc : SimClockFunctionList)
1654     {
1655         if (sc->prototype() == currentItem->text(0))
1656         {
1657             found = sc;
1658             break;
1659         }
1660     }
1661 
1662     if (found == nullptr)
1663     {
1664         sb->AddButton->setEnabled(false);
1665         qWarning() << i18n("Function index out of bounds.");
1666         return;
1667     }
1668 
1669     sb->AddButton->setEnabled(true);
1670     sb->FuncDoc->setHtml(found->description());
1671 }
1672 
1673 //Slots for Arg Widgets
1674 void ScriptBuilder::slotFindCity()
1675 {
1676     QPointer<LocationDialog> ld = new LocationDialog(this);
1677 
1678     if (ld->exec() == QDialog::Accepted)
1679     {
1680         if (ld->selectedCity())
1681         {
1682             // set new location names
1683             argSetGeoLocation->CityName->setText(ld->selectedCityName());
1684             if (!ld->selectedProvinceName().isEmpty())
1685             {
1686                 argSetGeoLocation->ProvinceName->setText(ld->selectedProvinceName());
1687             }
1688             else
1689             {
1690                 argSetGeoLocation->ProvinceName->clear();
1691             }
1692             argSetGeoLocation->CountryName->setText(ld->selectedCountryName());
1693 
1694             ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
1695             if (sf->name() == "setGeoLocation")
1696             {
1697                 setUnsavedChanges(true);
1698 
1699                 sf->setArg(0, ld->selectedCityName());
1700                 sf->setArg(1, ld->selectedProvinceName());
1701                 sf->setArg(2, ld->selectedCountryName());
1702             }
1703             else
1704             {
1705                 warningMismatch("setGeoLocation");
1706             }
1707         }
1708     }
1709     delete ld;
1710 }
1711 
1712 void ScriptBuilder::slotFindObject()
1713 {
1714     if (FindDialog::Instance()->exec() == QDialog::Accepted && FindDialog::Instance()->targetObject())
1715     {
1716         setUnsavedChanges(true);
1717 
1718         if (sender() == argLookToward->FindButton)
1719             argLookToward->FocusEdit->setEditText(FindDialog::Instance()->targetObject()->name());
1720         else
1721             argFindObject->NameEdit->setText(FindDialog::Instance()->targetObject()->name());
1722     }
1723 }
1724 
1725 void ScriptBuilder::slotShowOptions()
1726 {
1727     //Show tree-view of view options
1728     if (otv->exec() == QDialog::Accepted)
1729     {
1730         argChangeViewOption->OptionName->setCurrentIndex(
1731             argChangeViewOption->OptionName->findText(otv->optionsList()->currentItem()->text(0)));
1732     }
1733 }
1734 
1735 void ScriptBuilder::slotLookToward()
1736 {
1737     ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
1738 
1739     if (sf->name() == "lookTowards")
1740     {
1741         setUnsavedChanges(true);
1742 
1743         sf->setArg(0, argLookToward->FocusEdit->currentText());
1744         sf->setValid(true);
1745     }
1746     else
1747     {
1748         warningMismatch("lookTowards");
1749     }
1750 }
1751 
1752 void ScriptBuilder::slotArgFindObject()
1753 {
1754     ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
1755 
1756     if (sf->name() == "addLabel" || sf->name() == "removeLabel" || sf->name() == "addTrail" ||
1757             sf->name() == "removeTrail")
1758     {
1759         setUnsavedChanges(true);
1760 
1761         sf->setArg(0, argFindObject->NameEdit->text());
1762         sf->setValid(true);
1763     }
1764     else
1765     {
1766         warningMismatch(sf->name());
1767     }
1768 }
1769 
1770 void ScriptBuilder::slotRa()
1771 {
1772     ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
1773 
1774     if (sf->name() == "setRaDec")
1775     {
1776         //do nothing if box is blank (because we could be clearing boxes while switching argWidgets)
1777         if (argSetRaDec->RABox->text().isEmpty())
1778             return;
1779 
1780         bool ok(false);
1781         dms ra = argSetRaDec->RABox->createDms(&ok);
1782         if (ok)
1783         {
1784             setUnsavedChanges(true);
1785 
1786             sf->setArg(0, QString("%1").arg(ra.Hours()));
1787             if (!sf->argVal(1).isEmpty())
1788                 sf->setValid(true);
1789         }
1790         else
1791         {
1792             sf->setArg(0, QString());
1793             sf->setValid(false);
1794         }
1795     }
1796     else
1797     {
1798         warningMismatch("setRaDec");
1799     }
1800 }
1801 
1802 void ScriptBuilder::slotDec()
1803 {
1804     ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
1805 
1806     if (sf->name() == "setRaDec")
1807     {
1808         //do nothing if box is blank (because we could be clearing boxes while switching argWidgets)
1809         if (argSetRaDec->DecBox->text().isEmpty())
1810             return;
1811 
1812         bool ok(false);
1813         dms dec = argSetRaDec->DecBox->createDms(&ok);
1814         if (ok)
1815         {
1816             setUnsavedChanges(true);
1817 
1818             sf->setArg(1, QString("%1").arg(dec.Degrees()));
1819             if (!sf->argVal(0).isEmpty())
1820                 sf->setValid(true);
1821         }
1822         else
1823         {
1824             sf->setArg(1, QString());
1825             sf->setValid(false);
1826         }
1827     }
1828     else
1829     {
1830         warningMismatch("setRaDec");
1831     }
1832 }
1833 
1834 void ScriptBuilder::slotAz()
1835 {
1836     ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
1837 
1838     if (sf->name() == "setAltAz")
1839     {
1840         //do nothing if box is blank (because we could be clearing boxes while switching argWidgets)
1841         if (argSetAltAz->AzBox->text().isEmpty())
1842             return;
1843 
1844         bool ok(false);
1845         dms az = argSetAltAz->AzBox->createDms(&ok);
1846         if (ok)
1847         {
1848             setUnsavedChanges(true);
1849             sf->setArg(1, QString("%1").arg(az.Degrees()));
1850             if (!sf->argVal(0).isEmpty())
1851                 sf->setValid(true);
1852         }
1853         else
1854         {
1855             sf->setArg(1, QString());
1856             sf->setValid(false);
1857         }
1858     }
1859     else
1860     {
1861         warningMismatch("setAltAz");
1862     }
1863 }
1864 
1865 void ScriptBuilder::slotAlt()
1866 {
1867     ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
1868 
1869     if (sf->name() == "setAltAz")
1870     {
1871         //do nothing if box is blank (because we could be clearing boxes while switching argWidgets)
1872         if (argSetAltAz->AltBox->text().isEmpty())
1873             return;
1874 
1875         bool ok(false);
1876         dms alt = argSetAltAz->AltBox->createDms(&ok);
1877         if (ok)
1878         {
1879             setUnsavedChanges(true);
1880 
1881             sf->setArg(0, QString("%1").arg(alt.Degrees()));
1882             if (!sf->argVal(1).isEmpty())
1883                 sf->setValid(true);
1884         }
1885         else
1886         {
1887             sf->setArg(0, QString());
1888             sf->setValid(false);
1889         }
1890     }
1891     else
1892     {
1893         warningMismatch("setAltAz");
1894     }
1895 }
1896 
1897 void ScriptBuilder::slotChangeDate()
1898 {
1899     ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
1900 
1901     if (sf->name() == "setLocalTime")
1902     {
1903         setUnsavedChanges(true);
1904 
1905         QDate date = argSetLocalTime->DateWidget->date();
1906 
1907         sf->setArg(0, QString("%1").arg(date.year()));
1908         sf->setArg(1, QString("%1").arg(date.month()));
1909         sf->setArg(2, QString("%1").arg(date.day()));
1910         if (!sf->argVal(3).isEmpty())
1911             sf->setValid(true);
1912     }
1913     else
1914     {
1915         warningMismatch("setLocalTime");
1916     }
1917 }
1918 
1919 void ScriptBuilder::slotChangeTime()
1920 {
1921     ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
1922 
1923     if (sf->name() == "setLocalTime")
1924     {
1925         setUnsavedChanges(true);
1926 
1927         QTime time = argSetLocalTime->TimeBox->time();
1928 
1929         sf->setArg(3, QString("%1").arg(time.hour()));
1930         sf->setArg(4, QString("%1").arg(time.minute()));
1931         sf->setArg(5, QString("%1").arg(time.second()));
1932         if (!sf->argVal(0).isEmpty())
1933             sf->setValid(true);
1934     }
1935     else
1936     {
1937         warningMismatch("setLocalTime");
1938     }
1939 }
1940 
1941 void ScriptBuilder::slotWaitFor()
1942 {
1943     ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
1944 
1945     if (sf->name() == "waitFor")
1946     {
1947         bool ok(false);
1948         int delay = argWaitFor->DelayBox->text().toInt(&ok);
1949 
1950         if (ok)
1951         {
1952             setUnsavedChanges(true);
1953 
1954             sf->setArg(0, QString("%1").arg(delay));
1955             sf->setValid(true);
1956         }
1957         else
1958         {
1959             sf->setValid(false);
1960         }
1961     }
1962     else
1963     {
1964         warningMismatch("waitFor");
1965     }
1966 }
1967 
1968 void ScriptBuilder::slotWaitForKey()
1969 {
1970     ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
1971 
1972     if (sf->name() == "waitForKey")
1973     {
1974         QString sKey = argWaitForKey->WaitKeyEdit->text().trimmed();
1975 
1976         //DCOP script can only use single keystrokes; make sure entry is either one character,
1977         //or the word 'space'
1978         if (sKey.length() == 1 || sKey == "space")
1979         {
1980             setUnsavedChanges(true);
1981 
1982             sf->setArg(0, sKey);
1983             sf->setValid(true);
1984         }
1985         else
1986         {
1987             sf->setValid(false);
1988         }
1989     }
1990     else
1991     {
1992         warningMismatch("waitForKey");
1993     }
1994 }
1995 
1996 void ScriptBuilder::slotTracking()
1997 {
1998     ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
1999 
2000     if (sf->name() == "setTracking")
2001     {
2002         setUnsavedChanges(true);
2003 
2004         sf->setArg(0, (argSetTracking->CheckTrack->isChecked() ? i18n("true") : i18n("false")));
2005         sf->setValid(true);
2006     }
2007     else
2008     {
2009         warningMismatch("setTracking");
2010     }
2011 }
2012 
2013 void ScriptBuilder::slotViewOption()
2014 {
2015     ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
2016 
2017     if (sf->name() == "changeViewOption")
2018     {
2019         if (argChangeViewOption->OptionName->currentIndex() >= 0 && argChangeViewOption->OptionValue->text().length())
2020         {
2021             setUnsavedChanges(true);
2022 
2023             sf->setArg(0, argChangeViewOption->OptionName->currentText());
2024             sf->setArg(1, argChangeViewOption->OptionValue->text());
2025             sf->setValid(true);
2026         }
2027         else
2028         {
2029             sf->setValid(false);
2030         }
2031     }
2032     else
2033     {
2034         warningMismatch("changeViewOption");
2035     }
2036 }
2037 
2038 void ScriptBuilder::slotChangeCity()
2039 {
2040     ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
2041 
2042     if (sf->name() == "setGeoLocation")
2043     {
2044         QString city = argSetGeoLocation->CityName->text();
2045 
2046         if (city.length())
2047         {
2048             setUnsavedChanges(true);
2049 
2050             sf->setArg(0, city);
2051             if (sf->argVal(2).length())
2052                 sf->setValid(true);
2053         }
2054         else
2055         {
2056             sf->setArg(0, QString());
2057             sf->setValid(false);
2058         }
2059     }
2060     else
2061     {
2062         warningMismatch("setGeoLocation");
2063     }
2064 }
2065 
2066 void ScriptBuilder::slotChangeProvince()
2067 {
2068     ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
2069 
2070     if (sf->name() == "setGeoLocation")
2071     {
2072         QString province = argSetGeoLocation->ProvinceName->text();
2073 
2074         if (province.length())
2075         {
2076             setUnsavedChanges(true);
2077 
2078             sf->setArg(1, province);
2079             if (sf->argVal(0).length() && sf->argVal(2).length())
2080                 sf->setValid(true);
2081         }
2082         else
2083         {
2084             sf->setArg(1, QString());
2085             //might not be invalid
2086         }
2087     }
2088     else
2089     {
2090         warningMismatch("setGeoLocation");
2091     }
2092 }
2093 
2094 void ScriptBuilder::slotChangeCountry()
2095 {
2096     ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
2097 
2098     if (sf->name() == "setGeoLocation")
2099     {
2100         QString country = argSetGeoLocation->CountryName->text();
2101 
2102         if (country.length())
2103         {
2104             setUnsavedChanges(true);
2105 
2106             sf->setArg(2, country);
2107             if (sf->argVal(0).length())
2108                 sf->setValid(true);
2109         }
2110         else
2111         {
2112             sf->setArg(2, QString());
2113             sf->setValid(false);
2114         }
2115     }
2116     else
2117     {
2118         warningMismatch("setGeoLocation");
2119     }
2120 }
2121 
2122 void ScriptBuilder::slotTimeScale()
2123 {
2124     ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
2125 
2126     if (sf->name() == "setClockScale")
2127     {
2128         setUnsavedChanges(true);
2129 
2130         sf->setArg(0, QString("%1").arg(argTimeScale->TimeScale->tsbox()->timeScale()));
2131         sf->setValid(true);
2132     }
2133     else
2134     {
2135         warningMismatch("setClockScale");
2136     }
2137 }
2138 
2139 void ScriptBuilder::slotZoom()
2140 {
2141     ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
2142 
2143     if (sf->name() == "zoom")
2144     {
2145         setUnsavedChanges(true);
2146 
2147         bool ok(false);
2148         argZoom->ZoomBox->text().toDouble(&ok);
2149         if (ok)
2150         {
2151             sf->setArg(0, argZoom->ZoomBox->text());
2152             sf->setValid(true);
2153         }
2154     }
2155     else
2156     {
2157         warningMismatch("zoom");
2158     }
2159 }
2160 
2161 void ScriptBuilder::slotExportImage()
2162 {
2163     ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
2164 
2165     if (sf->name() == "exportImage")
2166     {
2167         setUnsavedChanges(true);
2168 
2169         sf->setArg(0, argExportImage->ExportFileName->url().url());
2170         sf->setArg(1, QString("%1").arg(argExportImage->ExportWidth->value()));
2171         sf->setArg(2, QString("%1").arg(argExportImage->ExportHeight->value()));
2172         sf->setValid(true);
2173     }
2174     else
2175     {
2176         warningMismatch("exportImage");
2177     }
2178 }
2179 
2180 void ScriptBuilder::slotPrintImage()
2181 {
2182     ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
2183 
2184     if (sf->name() == "printImage")
2185     {
2186         setUnsavedChanges(true);
2187 
2188         sf->setArg(0, (argPrintImage->UsePrintDialog->isChecked() ? i18n("true") : i18n("false")));
2189         sf->setArg(1, (argPrintImage->UseChartColors->isChecked() ? i18n("true") : i18n("false")));
2190         sf->setValid(true);
2191     }
2192     else
2193     {
2194         warningMismatch("exportImage");
2195     }
2196 }
2197 
2198 void ScriptBuilder::slotChangeColorName()
2199 {
2200     ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
2201 
2202     if (sf->name() == "setColor")
2203     {
2204         setUnsavedChanges(true);
2205 
2206         argSetColor->ColorValue->setColor(KStarsData::Instance()->colorScheme()->colorAt(argSetColor->ColorName->currentIndex()));
2207         sf->setArg(0, KStarsData::Instance()->colorScheme()->keyAt(argSetColor->ColorName->currentIndex()));
2208         QString cname(argSetColor->ColorValue->color().name());
2209         //if ( cname.at(0) == '#' ) cname = "\\" + cname; //prepend a "\" so bash doesn't think we have a comment
2210         sf->setArg(1, cname);
2211         sf->setValid(true);
2212     }
2213     else
2214     {
2215         warningMismatch("setColor");
2216     }
2217 }
2218 
2219 void ScriptBuilder::slotChangeColor()
2220 {
2221     ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
2222 
2223     if (sf->name() == "setColor")
2224     {
2225         setUnsavedChanges(true);
2226 
2227         sf->setArg(0, KStarsData::Instance()->colorScheme()->keyAt(argSetColor->ColorName->currentIndex()));
2228         QString cname(argSetColor->ColorValue->color().name());
2229         //if ( cname.at(0) == '#' ) cname = "\\" + cname; //prepend a "\" so bash doesn't think we have a comment
2230         sf->setArg(1, cname);
2231         sf->setValid(true);
2232     }
2233     else
2234     {
2235         warningMismatch("setColor");
2236     }
2237 }
2238 
2239 void ScriptBuilder::slotLoadColorScheme()
2240 {
2241     ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
2242 
2243     if (sf->name() == "loadColorScheme")
2244     {
2245         setUnsavedChanges(true);
2246 
2247         sf->setArg(0, '\"' + argLoadColorScheme->SchemeList->currentItem()->text() + '\"');
2248         sf->setValid(true);
2249     }
2250     else
2251     {
2252         warningMismatch("loadColorScheme");
2253     }
2254 }
2255 
2256 void ScriptBuilder::slotClose()
2257 {
2258     saveWarning();
2259 
2260     if (!UnsavedChanges)
2261     {
2262         ScriptList.clear();
2263         sb->ScriptListBox->clear();
2264         sb->ArgStack->setCurrentWidget(argBlank);
2265         close();
2266     }
2267 }
2268 
2269 //TODO JM: INDI Scripting to be included in KDE 4.1
2270 
2271 #if 0
2272 void ScriptBuilder::slotINDIStartDeviceName()
2273 {
2274     ScriptFunction * sf = ScriptList[ sb->ScriptListBox->currentRow() ];
2275 
2276     if ( sf->name() == "startINDI" )
2277     {
2278         setUnsavedChanges( true );
2279 
2280         sf->setArg(0, argStartINDI->deviceName->text());
2281         sf->setArg(1, argStartINDI->LocalButton->isChecked() ? "true" : "false");
2282         sf->setValid(true);
2283     }
2284     else
2285     {
2286         warningMismatch( "startINDI" );
2287     }
2288 
2289 }
2290 
2291 void ScriptBuilder::slotINDIStartDeviceMode()
2292 {
2293 
2294     ScriptFunction * sf = ScriptList[ sb->ScriptListBox->currentRow() ];
2295 
2296     if ( sf->name() == "startINDI" )
2297     {
2298         setUnsavedChanges( true );
2299 
2300         sf->setArg(1, argStartINDI->LocalButton->isChecked() ? "true" : "false");
2301         sf->setValid(true);
2302     }
2303     else
2304     {
2305         warningMismatch( "startINDI" );
2306     }
2307 
2308 }
2309 
2310 void ScriptBuilder::slotINDISetDevice()
2311 {
2312 
2313     ScriptFunction * sf = ScriptList[ sb->ScriptListBox->currentRow() ];
2314 
2315     if ( sf->name() == "setINDIDevice" )
2316     {
2317         setUnsavedChanges( true );
2318 
2319         sf->setArg(0, argSetDeviceINDI->deviceName->text());
2320         sf->setValid(true);
2321     }
2322     else
2323     {
2324         warningMismatch( "startINDI" );
2325     }
2326 }
2327 
2328 void ScriptBuilder::slotINDIShutdown()
2329 {
2330 
2331     ScriptFunction * sf = ScriptList[ sb->ScriptListBox->currentRow() ];
2332 
2333     if ( sf->name() == "shutdownINDI" )
2334     {
2335         if (argShutdownINDI->deviceName->text().isEmpty())
2336         {
2337             sf->setValid(false);
2338             return;
2339         }
2340 
2341         if (sf->argVal(0) != argShutdownINDI->deviceName->text())
2342             setUnsavedChanges( true );
2343 
2344         sf->setArg(0, argShutdownINDI->deviceName->text());
2345         sf->setValid(true);
2346     }
2347     else
2348     {
2349         warningMismatch( "shutdownINDI" );
2350     }
2351 
2352 }
2353 
2354 void ScriptBuilder::slotINDISwitchDeviceConnection()
2355 {
2356 
2357     ScriptFunction * sf = ScriptList[ sb->ScriptListBox->currentRow() ];
2358 
2359     if ( sf->name() == "switchINDI" )
2360     {
2361 
2362         if (sf->argVal(0) != (argSwitchINDI->OnButton->isChecked() ? "true" : "false"))
2363             setUnsavedChanges( true );
2364 
2365         sf->setArg(0, argSwitchINDI->OnButton->isChecked() ? "true" : "false");
2366         sf->setValid(true);
2367     }
2368     else
2369     {
2370         warningMismatch( "switchINDI" );
2371     }
2372 
2373 }
2374 
2375 void ScriptBuilder::slotINDISetPortDevicePort()
2376 {
2377     ScriptFunction * sf = ScriptList[ sb->ScriptListBox->currentRow() ];
2378 
2379     if ( sf->name() == "setINDIPort" )
2380     {
2381 
2382         if (argSetPortINDI->devicePort->text().isEmpty())
2383         {
2384             sf->setValid(false);
2385             return;
2386         }
2387 
2388         if (sf->argVal(0) != argSetPortINDI->devicePort->text())
2389             setUnsavedChanges( true );
2390 
2391         sf->setArg(0, argSetPortINDI->devicePort->text());
2392         sf->setValid(true);
2393     }
2394     else
2395     {
2396         warningMismatch( "setINDIPort" );
2397     }
2398 
2399 }
2400 
2401 void ScriptBuilder::slotINDISetTargetCoordDeviceRA()
2402 {
2403     ScriptFunction * sf = ScriptList[ sb->ScriptListBox->currentRow() ];
2404 
2405     if ( sf->name() == "setINDITargetCoord" )
2406     {
2407         //do nothing if box is blank (because we could be clearing boxes while switching argWidgets)
2408         if ( argSetTargetCoordINDI->RABox->text().isEmpty() )
2409         {
2410             sf->setValid(false);
2411             return;
2412         }
2413 
2414         bool ok(false);
2415         dms ra = argSetTargetCoordINDI->RABox->createDms(&ok);
2416         if ( ok )
2417         {
2418 
2419             if (sf->argVal(0) != QString( "%1" ).arg( ra.Hours() ))
2420                 setUnsavedChanges( true );
2421 
2422             sf->setArg( 0, QString( "%1" ).arg( ra.Hours() ) );
2423             if ( ( ! sf->argVal(1).isEmpty() ))
2424                 sf->setValid( true );
2425             else
2426                 sf->setValid(false);
2427 
2428         }
2429         else
2430         {
2431             sf->setArg( 0, QString() );
2432             sf->setValid( false );
2433         }
2434     }
2435     else
2436     {
2437         warningMismatch( "setINDITargetCoord" );
2438     }
2439 
2440 }
2441 
2442 void ScriptBuilder::slotINDISetTargetCoordDeviceDEC()
2443 {
2444     ScriptFunction * sf = ScriptList[ sb->ScriptListBox->currentRow() ];
2445 
2446     if ( sf->name() == "setINDITargetCoord" )
2447     {
2448         //do nothing if box is blank (because we could be clearing boxes while switching argWidgets)
2449         if ( argSetTargetCoordINDI->DecBox->text().isEmpty() )
2450         {
2451             sf->setValid(false);
2452             return;
2453         }
2454 
2455         bool ok(false);
2456         dms dec = argSetTargetCoordINDI->DecBox->createDms(&ok);
2457         if ( ok )
2458         {
2459 
2460             if (sf->argVal(1) != QString( "%1" ).arg( dec.Degrees() ))
2461                 setUnsavedChanges( true );
2462 
2463             sf->setArg( 1, QString( "%1" ).arg( dec.Degrees() ) );
2464             if ( ( ! sf->argVal(0).isEmpty() ))
2465                 sf->setValid( true );
2466             else
2467                 sf->setValid(false);
2468 
2469         }
2470         else
2471         {
2472             sf->setArg( 1, QString() );
2473             sf->setValid( false );
2474         }
2475     }
2476     else
2477     {
2478         warningMismatch( "setINDITargetCoord" );
2479     }
2480 
2481 }
2482 
2483 void ScriptBuilder::slotINDIsetCoreProperty(SequenceJob::SJ_TargetName,TargetName()
2484 {
2485 
2486     ScriptFunction * sf = ScriptList[ sb->ScriptListBox->currentRow() ];
2487 
2488     if ( sf->name() == "setINDITargetName" )
2489     {
2490         if (argsetCoreProperty(SequenceJob::SJ_TargetName,INDI->targetName->text().isEmpty())
2491         {
2492             sf->setValid(false);
2493             return;
2494         }
2495 
2496         if (sf->argVal(0) != argsetCoreProperty(SequenceJob::SJ_TargetName,INDI->targetName->text())
2497             setUnsavedChanges( true );
2498 
2499         sf->setArg(0, argsetCoreProperty(SequenceJob::SJ_TargetName,INDI->targetName->text());
2500         sf->setValid(true);
2501     }
2502     else
2503     {
2504         warningMismatch( "setINDITargetName" );
2505     }
2506 
2507 }
2508 
2509 void ScriptBuilder::slotINDISetActionName()
2510 {
2511     ScriptFunction * sf = ScriptList[ sb->ScriptListBox->currentRow() ];
2512 
2513     if ( sf->name() == "setINDIAction" )
2514     {
2515         if (argSetActionINDI->actionName->text().isEmpty())
2516         {
2517             sf->setValid(false);
2518             return;
2519         }
2520 
2521         if (sf->argVal(0) != argSetActionINDI->actionName->text())
2522             setUnsavedChanges( true );
2523 
2524         sf->setArg(0, argSetActionINDI->actionName->text());
2525         sf->setValid(true);
2526     }
2527     else
2528     {
2529         warningMismatch( "setINDIAction" );
2530     }
2531 
2532 }
2533 
2534 void ScriptBuilder::slotINDIWaitForActionName()
2535 {
2536     ScriptFunction * sf = ScriptList[ sb->ScriptListBox->currentRow() ];
2537 
2538     if ( sf->name() == "waitForINDIAction" )
2539     {
2540         if (argWaitForActionINDI->actionName->text().isEmpty())
2541         {
2542             sf->setValid(false);
2543             return;
2544         }
2545 
2546         if (sf->argVal(0) != argWaitForActionINDI->actionName->text())
2547             setUnsavedChanges( true );
2548 
2549         sf->setArg(0, argWaitForActionINDI->actionName->text());
2550         sf->setValid(true);
2551     }
2552     else
2553     {
2554         warningMismatch( "waitForINDIAction" );
2555     }
2556 
2557 }
2558 
2559 void ScriptBuilder::slotINDISetFocusSpeed()
2560 {
2561     ScriptFunction * sf = ScriptList[ sb->ScriptListBox->currentRow() ];
2562 
2563     if ( sf->name() == "setINDIFocusSpeed" )
2564     {
2565 
2566         if (sf->argVal(0).toInt() != argSetFocusSpeedINDI->speedIN->value())
2567             setUnsavedChanges( true );
2568 
2569         sf->setArg(0, QString("%1").arg(argSetFocusSpeedINDI->speedIN->value()));
2570         sf->setValid(true);
2571     }
2572     else
2573     {
2574         warningMismatch( "setINDIFocusSpeed" );
2575     }
2576 
2577 }
2578 
2579 void ScriptBuilder::slotINDIStartFocusDirection()
2580 {
2581     ScriptFunction * sf = ScriptList[ sb->ScriptListBox->currentRow() ];
2582 
2583     if ( sf->name() == "startINDIFocus" )
2584     {
2585         if (sf->argVal(0) != argStartFocusINDI->directionCombo->currentText())
2586             setUnsavedChanges( true );
2587 
2588         sf->setArg(0, argStartFocusINDI->directionCombo->currentText());
2589         sf->setValid(true);
2590     }
2591     else
2592     {
2593         warningMismatch( "startINDIFocus" );
2594     }
2595 
2596 }
2597 
2598 void ScriptBuilder::slotINDISetFocusTimeout()
2599 {
2600     ScriptFunction * sf = ScriptList[ sb->ScriptListBox->currentRow() ];
2601 
2602     if ( sf->name() == "setINDIFocusTimeout" )
2603     {
2604         if (sf->argVal(0).toInt() != argSetFocusTimeoutINDI->timeOut->value())
2605             setUnsavedChanges( true );
2606 
2607         sf->setArg(0, QString("%1").arg(argSetFocusTimeoutINDI->timeOut->value()));
2608         sf->setValid(true);
2609     }
2610     else
2611     {
2612         warningMismatch( "setINDIFocusTimeout" );
2613     }
2614 
2615 }
2616 
2617 void ScriptBuilder::slotINDISetGeoLocationDeviceLong()
2618 {
2619     ScriptFunction * sf = ScriptList[ sb->ScriptListBox->currentRow() ];
2620 
2621     if ( sf->name() == "setINDIGeoLocation" )
2622     {
2623         //do nothing if box is blank (because we could be clearing boxes while switching argWidgets)
2624         if ( argSetGeoLocationINDI->longBox->text().isEmpty())
2625         {
2626             sf->setValid(false);
2627             return;
2628         }
2629 
2630         bool ok(false);
2631         dms longitude = argSetGeoLocationINDI->longBox->createDms(&ok);
2632         if ( ok )
2633         {
2634 
2635             if (sf->argVal(0) != QString( "%1" ).arg( longitude.Degrees()))
2636                 setUnsavedChanges( true );
2637 
2638             sf->setArg( 0, QString( "%1" ).arg( longitude.Degrees() ) );
2639             if ( ! sf->argVal(1).isEmpty() )
2640                 sf->setValid( true );
2641             else
2642                 sf->setValid(false);
2643 
2644         }
2645         else
2646         {
2647             sf->setArg( 0, QString() );
2648             sf->setValid( false );
2649         }
2650     }
2651     else
2652     {
2653         warningMismatch( "setINDIGeoLocation" );
2654     }
2655 
2656 }
2657 
2658 void ScriptBuilder::slotINDISetGeoLocationDeviceLat()
2659 {
2660     ScriptFunction * sf = ScriptList[ sb->ScriptListBox->currentRow() ];
2661 
2662     if ( sf->name() == "setINDIGeoLocation" )
2663     {
2664         //do nothing if box is blank (because we could be clearing boxes while switching argWidgets)
2665         if ( argSetGeoLocationINDI->latBox->text().isEmpty() )
2666         {
2667             sf->setValid(false);
2668             return;
2669         }
2670 
2671         bool ok(false);
2672         dms latitude = argSetGeoLocationINDI->latBox->createDms(&ok);
2673         if ( ok )
2674         {
2675 
2676             if (sf->argVal(1) != QString( "%1" ).arg( latitude.Degrees()))
2677                 setUnsavedChanges( true );
2678 
2679             sf->setArg( 1, QString( "%1" ).arg( latitude.Degrees() ) );
2680             if ( ! sf->argVal(0).isEmpty() )
2681                 sf->setValid( true );
2682             else
2683                 sf->setValid(false);
2684 
2685         }
2686         else
2687         {
2688             sf->setArg( 1, QString() );
2689             sf->setValid( false );
2690         }
2691     }
2692     else
2693     {
2694         warningMismatch( "setINDIGeoLocation" );
2695     }
2696 
2697 }
2698 
2699 void ScriptBuilder::slotINDIStartExposureTimeout()
2700 {
2701     ScriptFunction * sf = ScriptList[ sb->ScriptListBox->currentRow() ];
2702 
2703     if ( sf->name() == "startINDIExposure" )
2704     {
2705 
2706         if (sf->argVal(0).toInt() != argStartExposureINDI->timeOut->value())
2707             setUnsavedChanges( true );
2708 
2709         sf->setArg(0, QString("%1").arg(argStartExposureINDI->timeOut->value()));
2710         sf->setValid(true);
2711     }
2712     else
2713     {
2714         warningMismatch( "startINDIExposure" );
2715     }
2716 
2717 }
2718 
2719 void ScriptBuilder::slotINDISetUTC()
2720 {
2721     ScriptFunction * sf = ScriptList[ sb->ScriptListBox->currentRow() ];
2722 
2723     if ( sf->name() == "setINDIUTC" )
2724     {
2725 
2726         if (argSetUTCINDI->UTC->text().isEmpty())
2727         {
2728             sf->setValid(false);
2729             return;
2730         }
2731 
2732         if (sf->argVal(0) != argSetUTCINDI->UTC->text())
2733             setUnsavedChanges( true );
2734 
2735         sf->setArg(0, argSetUTCINDI->UTC->text());
2736         sf->setValid(true);
2737     }
2738     else
2739     {
2740         warningMismatch( "setINDIUTC" );
2741     }
2742 
2743 }
2744 
2745 void ScriptBuilder::slotINDISetScopeAction()
2746 {
2747     ScriptFunction * sf = ScriptList[ sb->ScriptListBox->currentRow() ];
2748 
2749     if ( sf->name() == "setINDIScopeAction" )
2750     {
2751 
2752         if (sf->argVal(0) != argSetScopeActionINDI->actionCombo->currentText())
2753             setUnsavedChanges( true );
2754 
2755         sf->setArg(0, argSetScopeActionINDI->actionCombo->currentText());
2756         sf->setINDIProperty("CHECK");
2757         sf->setValid(true);
2758     }
2759     else
2760     {
2761         warningMismatch( "setINDIScopeAction" );
2762     }
2763 
2764 }
2765 
2766 void ScriptBuilder::slotINDISetFrameType()
2767 {
2768     ScriptFunction * sf = ScriptList[ sb->ScriptListBox->currentRow() ];
2769 
2770     if ( sf->name() == "setINDIFrameType" )
2771     {
2772 
2773         if (sf->argVal(0) != argSetFrameTypeINDI->typeCombo->currentText())
2774             setUnsavedChanges( true );
2775 
2776         sf->setArg(0, argSetFrameTypeINDI->typeCombo->currentText());
2777         sf->setValid(true);
2778     }
2779     else
2780     {
2781         warningMismatch( "setINDIFrameType" );
2782     }
2783 
2784 }
2785 
2786 void ScriptBuilder::slotINDISetCCDTemp()
2787 {
2788     ScriptFunction * sf = ScriptList[ sb->ScriptListBox->currentRow() ];
2789 
2790     if ( sf->name() == "setINDICCDTemp" )
2791     {
2792 
2793         if (sf->argVal(0).toInt() != argSetCCDTempINDI->temp->value())
2794             setUnsavedChanges( true );
2795 
2796         sf->setArg(0, QString("%1").arg(argSetCCDTempINDI->temp->value()));
2797         sf->setValid(true);
2798     }
2799     else
2800     {
2801         warningMismatch( "setINDICCDTemp" );
2802     }
2803 
2804 }
2805 
2806 void ScriptBuilder::slotINDISetFilterNum()
2807 {
2808 
2809     ScriptFunction * sf = ScriptList[ sb->ScriptListBox->currentRow() ];
2810 
2811     if ( sf->name() == "setINDIFilterNum" )
2812     {
2813 
2814         if (sf->argVal(0).toInt() != argSetFilterNumINDI->filter_num->value())
2815             setUnsavedChanges( true );
2816 
2817         sf->setArg(0, QString("%1").arg(argSetFilterNumINDI->filter_num->value()));
2818         sf->setValid(true);
2819     }
2820     else
2821     {
2822         warningMismatch( "setINDIFilterNum" );
2823     }
2824 
2825 
2826 }
2827 #endif
2828 
2829 void ScriptBuilder::warningMismatch(const QString &expected) const
2830 {
2831     qWarning() << i18n("Mismatch between function and Arg widget (expected %1.)", QString(expected));
2832 }