1 /*
2     SPDX-FileCopyrightText: 2003 Jason Harris <kstars@30doradus.org>
3 
4     SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 #include "scriptbuilder.h"
8 
9 #include "kspaths.h"
10 #include "scriptfunction.h"
11 #include "kstars.h"
12 #include "kstarsdata.h"
13 #include "skymap.h"
14 #include "ksnotification.h"
15 #include "kstarsdatetime.h"
16 #include "dialogs/finddialog.h"
17 #include "dialogs/locationdialog.h"
18 #include "widgets/dmsbox.h"
19 #include "widgets/timespinbox.h"
20 #include "widgets/timestepbox.h"
21 
22 #include <KLocalizedString>
23 #include <KMessageBox>
24 #include <KIO/StoredTransferJob>
25 #include <KIO/CopyJob>
26 #include <KJob>
27 
28 #include <QApplication>
29 #include <QFontMetrics>
30 #include <QTreeWidget>
31 #include <QTextStream>
32 #include <QFileDialog>
33 #include <QStandardPaths>
34 #include <QDebug>
35 
36 #include <sys/stat.h>
37 
OptionsTreeViewWidget(QWidget * p)38 OptionsTreeViewWidget::OptionsTreeViewWidget(QWidget *p) : QFrame(p)
39 {
40     setupUi(this);
41 }
42 
OptionsTreeView(QWidget * p)43 OptionsTreeView::OptionsTreeView(QWidget *p) : QDialog(p)
44 {
45     otvw.reset(new OptionsTreeViewWidget(this));
46 
47     QVBoxLayout *mainLayout = new QVBoxLayout;
48 
49     mainLayout->addWidget(otvw.get());
50     setLayout(mainLayout);
51 
52     setWindowTitle(i18nc("@title:window", "Options"));
53 
54     QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
55     mainLayout->addWidget(buttonBox);
56     connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
57     connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
58 
59     setModal(false);
60 }
61 
resizeColumns()62 void OptionsTreeView::resizeColumns()
63 {
64     //Size each column to the maximum width of items in that column
65     int maxwidth[3]  = { 0, 0, 0 };
66     QFontMetrics qfm = optionsList()->fontMetrics();
67 
68     for (int i = 0; i < optionsList()->topLevelItemCount(); ++i)
69     {
70         QTreeWidgetItem *topitem = optionsList()->topLevelItem(i);
71         topitem->setExpanded(true);
72 
73         for (int j = 0; j < topitem->childCount(); ++j)
74         {
75             QTreeWidgetItem *child = topitem->child(j);
76 
77             for (int icol = 0; icol < 3; ++icol)
78             {
79                 child->setExpanded(true);
80 
81 #if QT_VERSION >= QT_VERSION_CHECK(5,11,0)
82                 int w = qfm.horizontalAdvance(child->text(icol)) + 4;
83 #else
84                 int w = qfm.width(child->text(icol)) + 4;
85 #endif
86 
87                 if (icol == 0)
88                 {
89                     w += 2 * optionsList()->indentation();
90                 }
91 
92                 if (w > maxwidth[icol])
93                 {
94                     maxwidth[icol] = w;
95                 }
96             }
97         }
98     }
99 
100     for (int icol = 0; icol < 3; ++icol)
101     {
102         //DEBUG
103         qDebug() << QString("max width of column %1: %2").arg(icol).arg(maxwidth[icol]);
104 
105         optionsList()->setColumnWidth(icol, maxwidth[icol]);
106     }
107 }
108 
ScriptNameWidget(QWidget * p)109 ScriptNameWidget::ScriptNameWidget(QWidget *p) : QFrame(p)
110 {
111     setupUi(this);
112 }
113 
ScriptNameDialog(QWidget * p)114 ScriptNameDialog::ScriptNameDialog(QWidget *p) : QDialog(p)
115 {
116 #ifdef Q_OS_OSX
117     setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint);
118 #endif
119     snw = new ScriptNameWidget(this);
120 
121     QVBoxLayout *mainLayout = new QVBoxLayout;
122 
123     mainLayout->addWidget(snw);
124     setLayout(mainLayout);
125 
126     setWindowTitle(i18nc("@title:window", "Script Data"));
127 
128     QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
129     mainLayout->addWidget(buttonBox);
130     connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
131     connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
132 
133     okB = buttonBox->button(QDialogButtonBox::Ok);
134 
135     connect(snw->ScriptName, SIGNAL(textChanged(QString)), this, SLOT(slotEnableOkButton()));
136 }
137 
~ScriptNameDialog()138 ScriptNameDialog::~ScriptNameDialog()
139 {
140     delete snw;
141 }
142 
slotEnableOkButton()143 void ScriptNameDialog::slotEnableOkButton()
144 {
145     okB->setEnabled(!snw->ScriptName->text().isEmpty());
146 }
147 
ScriptBuilderUI(QWidget * p)148 ScriptBuilderUI::ScriptBuilderUI(QWidget *p) : QFrame(p)
149 {
150     setupUi(this);
151 }
152 
ScriptBuilder(QWidget * parent)153 ScriptBuilder::ScriptBuilder(QWidget *parent)
154     : QDialog(parent), UnsavedChanges(false), checkForChanges(true), currentFileURL(), currentDir(QDir::homePath()),
155       currentScriptName(), currentAuthor()
156 {
157 #ifdef Q_OS_OSX
158     setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint);
159 #endif
160     sb = new ScriptBuilderUI(this);
161 
162     QVBoxLayout *mainLayout = new QVBoxLayout;
163 
164     mainLayout->addWidget(sb);
165     setLayout(mainLayout);
166 
167     setWindowTitle(i18nc("@title:window", "Script Builder"));
168 
169     QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close);
170     mainLayout->addWidget(buttonBox);
171     connect(buttonBox, SIGNAL(rejected()), this, SLOT(slotClose()));
172 
173     sb->FuncDoc->setTextInteractionFlags(Qt::NoTextInteraction);
174 
175     //Initialize function templates and descriptions
176     KStarsFunctionList.append(new ScriptFunction("lookTowards",
177                               i18n("Point the display at the specified location. %1 can be the name "
178                                    "of an object, a cardinal point on the compass, or 'zenith'.",
179                                    QString("dir")),
180                               false, "QString", "dir"));
181     KStarsFunctionList.append(new ScriptFunction(
182                                   "addLabel", i18n("Add a name label to the object named %1.", QString("name")), false, "QString", "name"));
183     KStarsFunctionList.append(
184         new ScriptFunction("removeLabel", i18n("Remove the name label from the object named %1.", QString("name")),
185                            false, "QString", "name"));
186     KStarsFunctionList.append(new ScriptFunction(
187                                   "addTrail", i18n("Add a trail to the solar system body named %1.", QString("name")), false, "QString", "name"));
188     KStarsFunctionList.append(new ScriptFunction(
189                                   "removeTrail", i18n("Remove the trail from the solar system body named %1.", QString("name")), false, "QString",
190                                   "name"));
191     KStarsFunctionList.append(new ScriptFunction("setRaDec",
192                               i18n("Point the display at the specified RA/Dec coordinates.  RA is "
193                                    "expressed in Hours; Dec is expressed in Degrees."),
194                               false, "double", "ra", "double", "dec"));
195     KStarsFunctionList.append(new ScriptFunction(
196                                   "setAltAz",
197                                   i18n("Point the display at the specified Alt/Az coordinates.  Alt and Az are expressed in Degrees."), false,
198                                   "double", "alt", "double", "az"));
199     KStarsFunctionList.append(new ScriptFunction("zoomIn", i18n("Increase the display Zoom Level."), false));
200     KStarsFunctionList.append(new ScriptFunction("zoomOut", i18n("Decrease the display Zoom Level."), false));
201     KStarsFunctionList.append(
202         new ScriptFunction("defaultZoom", i18n("Set the display Zoom Level to its default value."), false));
203     KStarsFunctionList.append(
204         new ScriptFunction("zoom", i18n("Set the display Zoom Level manually."), false, "double", "z"));
205     KStarsFunctionList.append(
206         new ScriptFunction("setLocalTime", i18n("Set the system clock to the specified Local Time."), false, "int",
207                            "year", "int", "month", "int", "day", "int", "hour", "int", "minute", "int", "second"));
208     KStarsFunctionList.append(new ScriptFunction(
209                                   "waitFor", i18n("Pause script execution for specified number of seconds."), false, "double", "sec"));
210     KStarsFunctionList.append(new ScriptFunction("waitForKey",
211                               i18n("Halt script execution until the specified key is pressed.  Only "
212                                    "single-key strokes are possible; use 'space' for the spacebar."),
213                               false, "QString", "key"));
214     KStarsFunctionList.append(new ScriptFunction(
215                                   "setTracking", i18n("Set whether the display is tracking the current location."), false, "bool", "track"));
216     KStarsFunctionList.append(new ScriptFunction(
217                                   "changeViewOption", i18n("Change view option named %1 to value %2.", QString("opName"), QString("opValue")),
218                                   false, "QString", "opName", "QString", "opValue"));
219     KStarsFunctionList.append(new ScriptFunction(
220                                   "setGeoLocation", i18n("Set the geographic location to the city specified by city, province and country."),
221                                   false, "QString", "cityName", "QString", "provinceName", "QString", "countryName"));
222     KStarsFunctionList.append(new ScriptFunction(
223                                   "setColor", i18n("Set the color named %1 to the value %2.", QString("colorName"), QString("value")), false,
224                                   "QString", "colorName", "QString", "value"));
225     KStarsFunctionList.append(new ScriptFunction("loadColorScheme", i18n("Load the color scheme specified by name."),
226                               false, "QString", "name"));
227     KStarsFunctionList.append(
228         new ScriptFunction("exportImage", i18n("Export the sky image to the file, with specified width and height."),
229                            false, "QString", "fileName", "int", "width", "int", "height"));
230     KStarsFunctionList.append(
231         new ScriptFunction("printImage",
232                            i18n("Print the sky image to a printer or file.  If %1 is true, it will show the print "
233                                 "dialog.  If %2 is true, it will use the Star Chart color scheme for printing.",
234                                 QString("usePrintDialog"), QString("useChartColors")),
235                            false, "bool", "usePrintDialog", "bool", "useChartColors"));
236     SimClockFunctionList.append(new ScriptFunction("stop", i18n("Halt the simulation clock."), true));
237     SimClockFunctionList.append(new ScriptFunction("start", i18n("Start the simulation clock."), true));
238     SimClockFunctionList.append(new ScriptFunction("setClockScale",
239                                 i18n("Set the timescale of the simulation clock to specified scale. "
240                                      " 1.0 means real-time; 2.0 means twice real-time; etc."),
241                                 true, "double", "scale"));
242 
243     // JM: We're using QTreeWdiget for Qt4 now
244     QTreeWidgetItem *kstars_tree   = new QTreeWidgetItem(sb->FunctionTree, QStringList("KStars"));
245     QTreeWidgetItem *simclock_tree = new QTreeWidgetItem(sb->FunctionTree, QStringList("SimClock"));
246 
247     for (auto &item : KStarsFunctionList)
248         new QTreeWidgetItem(kstars_tree, QStringList(item->prototype()));
249 
250     for (auto &item : SimClockFunctionList)
251         new QTreeWidgetItem(simclock_tree, QStringList(item->prototype()));
252 
253     kstars_tree->sortChildren(0, Qt::AscendingOrder);
254     simclock_tree->sortChildren(0, Qt::AscendingOrder);
255 
256     sb->FunctionTree->setColumnCount(1);
257     sb->FunctionTree->setHeaderLabels(QStringList(i18n("Functions")));
258     sb->FunctionTree->setSortingEnabled(false);
259 
260     //Add icons to Push Buttons
261     sb->NewButton->setIcon(QIcon::fromTheme("document-new"));
262     sb->OpenButton->setIcon(QIcon::fromTheme("document-open"));
263     sb->SaveButton->setIcon(QIcon::fromTheme("document-save"));
264     sb->SaveAsButton->setIcon(
265         QIcon::fromTheme("document-save-as"));
266     sb->RunButton->setIcon(QIcon::fromTheme("system-run"));
267     sb->CopyButton->setIcon(QIcon::fromTheme("view-refresh"));
268     sb->AddButton->setIcon(QIcon::fromTheme("go-previous"));
269     sb->RemoveButton->setIcon(QIcon::fromTheme("go-next"));
270     sb->UpButton->setIcon(QIcon::fromTheme("go-up"));
271     sb->DownButton->setIcon(QIcon::fromTheme("go-down"));
272 
273     sb->NewButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
274     sb->OpenButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
275     sb->SaveButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
276     sb->SaveAsButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
277     sb->RunButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
278     sb->CopyButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
279     sb->AddButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
280     sb->RemoveButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
281     sb->UpButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
282     sb->DownButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
283 
284     //Prepare the widget stack
285     argBlank            = new QWidget();
286     argLookToward       = new ArgLookToward(sb->ArgStack);
287     argFindObject       = new ArgFindObject(sb->ArgStack); //shared by Add/RemoveLabel and Add/RemoveTrail
288     argSetRaDec         = new ArgSetRaDec(sb->ArgStack);
289     argSetAltAz         = new ArgSetAltAz(sb->ArgStack);
290     argSetLocalTime     = new ArgSetLocalTime(sb->ArgStack);
291     argWaitFor          = new ArgWaitFor(sb->ArgStack);
292     argWaitForKey       = new ArgWaitForKey(sb->ArgStack);
293     argSetTracking      = new ArgSetTrack(sb->ArgStack);
294     argChangeViewOption = new ArgChangeViewOption(sb->ArgStack);
295     argSetGeoLocation   = new ArgSetGeoLocation(sb->ArgStack);
296     argTimeScale        = new ArgTimeScale(sb->ArgStack);
297     argZoom             = new ArgZoom(sb->ArgStack);
298     argExportImage      = new ArgExportImage(sb->ArgStack);
299     argPrintImage       = new ArgPrintImage(sb->ArgStack);
300     argSetColor         = new ArgSetColor(sb->ArgStack);
301     argLoadColorScheme  = new ArgLoadColorScheme(sb->ArgStack);
302 
303     sb->ArgStack->addWidget(argBlank);
304     sb->ArgStack->addWidget(argLookToward);
305     sb->ArgStack->addWidget(argFindObject);
306     sb->ArgStack->addWidget(argSetRaDec);
307     sb->ArgStack->addWidget(argSetAltAz);
308     sb->ArgStack->addWidget(argSetLocalTime);
309     sb->ArgStack->addWidget(argWaitFor);
310     sb->ArgStack->addWidget(argWaitForKey);
311     sb->ArgStack->addWidget(argSetTracking);
312     sb->ArgStack->addWidget(argChangeViewOption);
313     sb->ArgStack->addWidget(argSetGeoLocation);
314     sb->ArgStack->addWidget(argTimeScale);
315     sb->ArgStack->addWidget(argZoom);
316     sb->ArgStack->addWidget(argExportImage);
317     sb->ArgStack->addWidget(argPrintImage);
318     sb->ArgStack->addWidget(argSetColor);
319     sb->ArgStack->addWidget(argLoadColorScheme);
320 
321     sb->ArgStack->setCurrentIndex(0);
322 
323     snd = new ScriptNameDialog(KStars::Instance());
324     otv = new OptionsTreeView(KStars::Instance());
325 
326     otv->resize(sb->width(), 0.5 * sb->height());
327 
328     initViewOptions();
329     otv->resizeColumns();
330 
331     //connect widgets in ScriptBuilderUI
332     connect(sb->FunctionTree, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(slotAddFunction()));
333     connect(sb->FunctionTree, SIGNAL(itemClicked(QTreeWidgetItem*, int)), this, SLOT(slotShowDoc()));
334     connect(sb->UpButton, SIGNAL(clicked()), this, SLOT(slotMoveFunctionUp()));
335     connect(sb->ScriptListBox, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(slotArgWidget()));
336     connect(sb->DownButton, SIGNAL(clicked()), this, SLOT(slotMoveFunctionDown()));
337     connect(sb->CopyButton, SIGNAL(clicked()), this, SLOT(slotCopyFunction()));
338     connect(sb->RemoveButton, SIGNAL(clicked()), this, SLOT(slotRemoveFunction()));
339     connect(sb->NewButton, SIGNAL(clicked()), this, SLOT(slotNew()));
340     connect(sb->OpenButton, SIGNAL(clicked()), this, SLOT(slotOpen()));
341     connect(sb->SaveButton, SIGNAL(clicked()), this, SLOT(slotSave()));
342     connect(sb->SaveAsButton, SIGNAL(clicked()), this, SLOT(slotSaveAs()));
343     connect(sb->AddButton, SIGNAL(clicked()), this, SLOT(slotAddFunction()));
344     connect(sb->RunButton, SIGNAL(clicked()), this, SLOT(slotRunScript()));
345 
346     //Connections for Arg Widgets
347     connect(argSetGeoLocation->FindCityButton, SIGNAL(clicked()), this, SLOT(slotFindCity()));
348     connect(argLookToward->FindButton, SIGNAL(clicked()), this, SLOT(slotFindObject()));
349     connect(argChangeViewOption->TreeButton, SIGNAL(clicked()), this, SLOT(slotShowOptions()));
350     connect(argFindObject->FindButton, SIGNAL(clicked()), this, SLOT(slotFindObject()));
351 
352     connect(argLookToward->FocusEdit, SIGNAL(editTextChanged(QString)), this, SLOT(slotLookToward()));
353     connect(argFindObject->NameEdit, SIGNAL(textChanged(QString)), this, SLOT(slotArgFindObject()));
354     connect(argSetRaDec->RABox, SIGNAL(textChanged(QString)), this, SLOT(slotRa()));
355     connect(argSetRaDec->DecBox, SIGNAL(textChanged(QString)), this, SLOT(slotDec()));
356     connect(argSetAltAz->AltBox, SIGNAL(textChanged(QString)), this, SLOT(slotAlt()));
357     connect(argSetAltAz->AzBox, SIGNAL(textChanged(QString)), this, SLOT(slotAz()));
358     connect(argSetLocalTime->DateWidget, SIGNAL(dateChanged(QDate)), this, SLOT(slotChangeDate()));
359     connect(argSetLocalTime->TimeBox, SIGNAL(timeChanged(QTime)), this, SLOT(slotChangeTime()));
360     connect(argWaitFor->DelayBox, SIGNAL(valueChanged(int)), this, SLOT(slotWaitFor()));
361     connect(argWaitForKey->WaitKeyEdit, SIGNAL(textChanged(QString)), this, SLOT(slotWaitForKey()));
362     connect(argSetTracking->CheckTrack, SIGNAL(stateChanged(int)), this, SLOT(slotTracking()));
363     connect(argChangeViewOption->OptionName, SIGNAL(activated(QString)), this, SLOT(slotViewOption()));
364     connect(argChangeViewOption->OptionValue, SIGNAL(textChanged(QString)), this, SLOT(slotViewOption()));
365     connect(argSetGeoLocation->CityName, SIGNAL(textChanged(QString)), this, SLOT(slotChangeCity()));
366     connect(argSetGeoLocation->ProvinceName, SIGNAL(textChanged(QString)), this, SLOT(slotChangeProvince()));
367     connect(argSetGeoLocation->CountryName, SIGNAL(textChanged(QString)), this, SLOT(slotChangeCountry()));
368     connect(argTimeScale->TimeScale, SIGNAL(scaleChanged(float)), this, SLOT(slotTimeScale()));
369     connect(argZoom->ZoomBox, SIGNAL(textChanged(QString)), this, SLOT(slotZoom()));
370     connect(argExportImage->ExportFileName, SIGNAL(textChanged(QString)), this, SLOT(slotExportImage()));
371     connect(argExportImage->ExportWidth, SIGNAL(valueChanged(int)), this, SLOT(slotExportImage()));
372     connect(argExportImage->ExportHeight, SIGNAL(valueChanged(int)), this, SLOT(slotExportImage()));
373     connect(argPrintImage->UsePrintDialog, SIGNAL(toggled(bool)), this, SLOT(slotPrintImage()));
374     connect(argPrintImage->UseChartColors, SIGNAL(toggled(bool)), this, SLOT(slotPrintImage()));
375     connect(argSetColor->ColorName, SIGNAL(activated(QString)), this, SLOT(slotChangeColorName()));
376     connect(argSetColor->ColorValue, SIGNAL(changed(QColor)), this, SLOT(slotChangeColor()));
377     connect(argLoadColorScheme->SchemeList, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(slotLoadColorScheme()));
378 
379     //disable some buttons
380     sb->CopyButton->setEnabled(false);
381     sb->AddButton->setEnabled(false);
382     sb->RemoveButton->setEnabled(false);
383     sb->UpButton->setEnabled(false);
384     sb->DownButton->setEnabled(false);
385     sb->SaveButton->setEnabled(false);
386     sb->SaveAsButton->setEnabled(false);
387     sb->RunButton->setEnabled(false);
388 }
389 
~ScriptBuilder()390 ScriptBuilder::~ScriptBuilder()
391 {
392     while (!KStarsFunctionList.isEmpty())
393         delete KStarsFunctionList.takeFirst();
394 
395     while (!SimClockFunctionList.isEmpty())
396         delete SimClockFunctionList.takeFirst();
397 
398     while (!ScriptList.isEmpty())
399         delete ScriptList.takeFirst();
400 }
401 
initViewOptions()402 void ScriptBuilder::initViewOptions()
403 {
404     otv->optionsList()->setRootIsDecorated(true);
405     QStringList fields;
406 
407     //InfoBoxes
408     opsGUI = new QTreeWidgetItem(otv->optionsList(), QStringList(i18n("InfoBoxes")));
409     fields << "ShowInfoBoxes" << i18n("Toggle display of all InfoBoxes") << i18n("bool");
410     new QTreeWidgetItem(opsGUI, fields);
411     fields.clear();
412     fields << "ShowTimeBox" << i18n("Toggle display of Time InfoBox") << i18n("bool");
413     new QTreeWidgetItem(opsGUI, fields);
414     fields.clear();
415     fields << "ShowGeoBox" << i18n("Toggle display of Geographic InfoBox") << i18n("bool");
416     new QTreeWidgetItem(opsGUI, fields);
417     fields.clear();
418     fields << "ShowFocusBox" << i18n("Toggle display of Focus InfoBox") << i18n("bool");
419     new QTreeWidgetItem(opsGUI, fields);
420     fields.clear();
421     fields << "ShadeTimeBox" << i18n("(un)Shade Time InfoBox") << i18n("bool");
422     new QTreeWidgetItem(opsGUI, fields);
423     fields.clear();
424     fields << "ShadeGeoBox" << i18n("(un)Shade Geographic InfoBox") << i18n("bool");
425     new QTreeWidgetItem(opsGUI, fields);
426     fields.clear();
427     fields << "ShadeFocusBox" << i18n("(un)Shade Focus InfoBox") << i18n("bool");
428     new QTreeWidgetItem(opsGUI, fields);
429     fields.clear();
430 
431     argChangeViewOption->OptionName->addItem("ShowInfoBoxes");
432     argChangeViewOption->OptionName->addItem("ShowTimeBox");
433     argChangeViewOption->OptionName->addItem("ShowGeoBox");
434     argChangeViewOption->OptionName->addItem("ShowFocusBox");
435     argChangeViewOption->OptionName->addItem("ShadeTimeBox");
436     argChangeViewOption->OptionName->addItem("ShadeGeoBox");
437     argChangeViewOption->OptionName->addItem("ShadeFocusBox");
438 
439     //Toolbars
440     opsToolbar = new QTreeWidgetItem(otv->optionsList(), QStringList(i18n("Toolbars")));
441     fields << "ShowMainToolBar" << i18n("Toggle display of main toolbar") << i18n("bool");
442     new QTreeWidgetItem(opsToolbar, fields);
443     fields.clear();
444     fields << "ShowViewToolBar" << i18n("Toggle display of view toolbar") << i18n("bool");
445     new QTreeWidgetItem(opsToolbar, fields);
446     fields.clear();
447 
448     argChangeViewOption->OptionName->addItem("ShowMainToolBar");
449     argChangeViewOption->OptionName->addItem("ShowViewToolBar");
450 
451     //Show Objects
452     opsShowObj = new QTreeWidgetItem(otv->optionsList(), QStringList(i18n("Show Objects")));
453     fields << "ShowStars" << i18n("Toggle display of Stars") << i18n("bool");
454     new QTreeWidgetItem(opsShowObj, fields);
455     fields.clear();
456     fields << "ShowDeepSky" << i18n("Toggle display of all deep-sky objects") << i18n("bool");
457     new QTreeWidgetItem(opsShowObj, fields);
458     fields.clear();
459     new QTreeWidgetItem(opsShowObj, fields);
460     fields.clear();
461     new QTreeWidgetItem(opsShowObj, fields);
462     fields.clear();
463     fields << "ShowSolarSystem" << i18n("Toggle display of all solar system bodies") << i18n("bool");
464     new QTreeWidgetItem(opsShowObj, fields);
465     fields.clear();
466     fields << "ShowSun" << i18n("Toggle display of Sun") << i18n("bool");
467     new QTreeWidgetItem(opsShowObj, fields);
468     fields.clear();
469     fields << "ShowMoon" << i18n("Toggle display of Moon") << i18n("bool");
470     new QTreeWidgetItem(opsShowObj, fields);
471     fields.clear();
472     fields << "ShowMercury" << i18n("Toggle display of Mercury") << i18n("bool");
473     new QTreeWidgetItem(opsShowObj, fields);
474     fields.clear();
475     fields << "ShowVenus" << i18n("Toggle display of Venus") << i18n("bool");
476     new QTreeWidgetItem(opsShowObj, fields);
477     fields.clear();
478     fields << "ShowMars" << i18n("Toggle display of Mars") << i18n("bool");
479     new QTreeWidgetItem(opsShowObj, fields);
480     fields.clear();
481     fields << "ShowJupiter" << i18n("Toggle display of Jupiter") << i18n("bool");
482     new QTreeWidgetItem(opsShowObj, fields);
483     fields.clear();
484     fields << "ShowSaturn" << i18n("Toggle display of Saturn") << i18n("bool");
485     new QTreeWidgetItem(opsShowObj, fields);
486     fields.clear();
487     fields << "ShowUranus" << i18n("Toggle display of Uranus") << i18n("bool");
488     new QTreeWidgetItem(opsShowObj, fields);
489     fields.clear();
490     fields << "ShowNeptune" << i18n("Toggle display of Neptune") << i18n("bool");
491     new QTreeWidgetItem(opsShowObj, fields);
492     //fields.clear();
493     //fields << "ShowPluto" << i18n( "Toggle display of Pluto" ) << i18n( "bool" );
494     //new QTreeWidgetItem( opsShowObj, fields );
495     fields.clear();
496     fields << "ShowAsteroids" << i18n("Toggle display of Asteroids") << i18n("bool");
497     new QTreeWidgetItem(opsShowObj, fields);
498     fields.clear();
499     fields << "ShowComets" << i18n("Toggle display of Comets") << i18n("bool");
500     new QTreeWidgetItem(opsShowObj, fields);
501     fields.clear();
502 
503     argChangeViewOption->OptionName->addItem("ShowStars");
504     argChangeViewOption->OptionName->addItem("ShowDeepSky");
505     argChangeViewOption->OptionName->addItem("ShowSolarSystem");
506     argChangeViewOption->OptionName->addItem("ShowSun");
507     argChangeViewOption->OptionName->addItem("ShowMoon");
508     argChangeViewOption->OptionName->addItem("ShowMercury");
509     argChangeViewOption->OptionName->addItem("ShowVenus");
510     argChangeViewOption->OptionName->addItem("ShowMars");
511     argChangeViewOption->OptionName->addItem("ShowJupiter");
512     argChangeViewOption->OptionName->addItem("ShowSaturn");
513     argChangeViewOption->OptionName->addItem("ShowUranus");
514     argChangeViewOption->OptionName->addItem("ShowNeptune");
515     //argChangeViewOption->OptionName->addItem( "ShowPluto" );
516     argChangeViewOption->OptionName->addItem("ShowAsteroids");
517     argChangeViewOption->OptionName->addItem("ShowComets");
518 
519     opsShowOther = new QTreeWidgetItem(otv->optionsList(), QStringList(i18n("Show Other")));
520     fields << "ShowCLines" << i18n("Toggle display of constellation lines") << i18n("bool");
521     new QTreeWidgetItem(opsShowOther, fields);
522     fields.clear();
523     fields << "ShowCBounds" << i18n("Toggle display of constellation boundaries") << i18n("bool");
524     new QTreeWidgetItem(opsShowOther, fields);
525     fields.clear();
526     fields << "ShowCNames" << i18n("Toggle display of constellation names") << i18n("bool");
527     new QTreeWidgetItem(opsShowOther, fields);
528     fields.clear();
529     fields << "ShowMilkyWay" << i18n("Toggle display of Milky Way") << i18n("bool");
530     new QTreeWidgetItem(opsShowOther, fields);
531     fields.clear();
532     fields << "ShowGrid" << i18n("Toggle display of the coordinate grid") << i18n("bool");
533     new QTreeWidgetItem(opsShowOther, fields);
534     fields.clear();
535     fields << "ShowEquator" << i18n("Toggle display of the celestial equator") << i18n("bool");
536     new QTreeWidgetItem(opsShowOther, fields);
537     fields.clear();
538     fields << "ShowEcliptic" << i18n("Toggle display of the ecliptic") << i18n("bool");
539     new QTreeWidgetItem(opsShowOther, fields);
540     fields.clear();
541     fields << "ShowHorizon" << i18n("Toggle display of the horizon line") << i18n("bool");
542     new QTreeWidgetItem(opsShowOther, fields);
543     fields.clear();
544     fields << "ShowGround" << i18n("Toggle display of the opaque ground") << i18n("bool");
545     new QTreeWidgetItem(opsShowOther, fields);
546     fields.clear();
547     fields << "ShowStarNames" << i18n("Toggle display of star name labels") << i18n("bool");
548     new QTreeWidgetItem(opsShowOther, fields);
549     fields.clear();
550     fields << "ShowStarMagnitudes" << i18n("Toggle display of star magnitude labels") << i18n("bool");
551     new QTreeWidgetItem(opsShowOther, fields);
552     fields.clear();
553     fields << "ShowAsteroidNames" << i18n("Toggle display of asteroid name labels") << i18n("bool");
554     new QTreeWidgetItem(opsShowOther, fields);
555     fields.clear();
556     fields << "ShowCometNames" << i18n("Toggle display of comet name labels") << i18n("bool");
557     new QTreeWidgetItem(opsShowOther, fields);
558     fields.clear();
559     fields << "ShowPlanetNames" << i18n("Toggle display of planet name labels") << i18n("bool");
560     new QTreeWidgetItem(opsShowOther, fields);
561     fields.clear();
562     fields << "ShowPlanetImages" << i18n("Toggle display of planet images") << i18n("bool");
563     new QTreeWidgetItem(opsShowOther, fields);
564     fields.clear();
565 
566     argChangeViewOption->OptionName->addItem("ShowCLines");
567     argChangeViewOption->OptionName->addItem("ShowCBounds");
568     argChangeViewOption->OptionName->addItem("ShowCNames");
569     argChangeViewOption->OptionName->addItem("ShowMilkyWay");
570     argChangeViewOption->OptionName->addItem("ShowGrid");
571     argChangeViewOption->OptionName->addItem("ShowEquator");
572     argChangeViewOption->OptionName->addItem("ShowEcliptic");
573     argChangeViewOption->OptionName->addItem("ShowHorizon");
574     argChangeViewOption->OptionName->addItem("ShowGround");
575     argChangeViewOption->OptionName->addItem("ShowStarNames");
576     argChangeViewOption->OptionName->addItem("ShowStarMagnitudes");
577     argChangeViewOption->OptionName->addItem("ShowAsteroidNames");
578     argChangeViewOption->OptionName->addItem("ShowCometNames");
579     argChangeViewOption->OptionName->addItem("ShowPlanetNames");
580     argChangeViewOption->OptionName->addItem("ShowPlanetImages");
581 
582     opsCName = new QTreeWidgetItem(otv->optionsList(), QStringList(i18n("Constellation Names")));
583     fields << "UseLatinConstellNames" << i18n("Show Latin constellation names") << i18n("bool");
584     new QTreeWidgetItem(opsCName, fields);
585     fields.clear();
586     fields << "UseLocalConstellNames" << i18n("Show constellation names in local language") << i18n("bool");
587     new QTreeWidgetItem(opsCName, fields);
588     fields.clear();
589     fields << "UseAbbrevConstellNames" << i18n("Show IAU-standard constellation abbreviations") << i18n("bool");
590     new QTreeWidgetItem(opsCName, fields);
591     fields.clear();
592 
593     argChangeViewOption->OptionName->addItem("UseLatinConstellNames");
594     argChangeViewOption->OptionName->addItem("UseLocalConstellNames");
595     argChangeViewOption->OptionName->addItem("UseAbbrevConstellNames");
596 
597     opsHide = new QTreeWidgetItem(otv->optionsList(), QStringList(i18n("Hide Items")));
598     fields << "HideOnSlew" << i18n("Toggle whether objects hidden while slewing display") << i18n("bool");
599     new QTreeWidgetItem(opsHide, fields);
600     fields.clear();
601     fields << "SlewTimeScale" << i18n("Timestep threshold (in seconds) for hiding objects") << i18n("double");
602     new QTreeWidgetItem(opsHide, fields);
603     fields.clear();
604     fields << "HideStars" << i18n("Hide faint stars while slewing?") << i18n("bool");
605     new QTreeWidgetItem(opsHide, fields);
606     fields.clear();
607     fields << "HidePlanets" << i18n("Hide solar system bodies while slewing?") << i18n("bool");
608     new QTreeWidgetItem(opsHide, fields);
609     fields.clear();
610     fields << "HideMilkyWay" << i18n("Hide Milky Way while slewing?") << i18n("bool");
611     new QTreeWidgetItem(opsHide, fields);
612     fields.clear();
613     fields << "HideCNames" << i18n("Hide constellation names while slewing?") << i18n("bool");
614     new QTreeWidgetItem(opsHide, fields);
615     fields.clear();
616     fields << "HideCLines" << i18n("Hide constellation lines while slewing?") << i18n("bool");
617     new QTreeWidgetItem(opsHide, fields);
618     fields.clear();
619     fields << "HideCBounds" << i18n("Hide constellation boundaries while slewing?") << i18n("bool");
620     new QTreeWidgetItem(opsHide, fields);
621     fields.clear();
622     fields << "HideGrid" << i18n("Hide coordinate grid while slewing?") << i18n("bool");
623     new QTreeWidgetItem(opsHide, fields);
624     fields.clear();
625 
626     argChangeViewOption->OptionName->addItem("HideOnSlew");
627     argChangeViewOption->OptionName->addItem("SlewTimeScale");
628     argChangeViewOption->OptionName->addItem("HideStars");
629     argChangeViewOption->OptionName->addItem("HidePlanets");
630     argChangeViewOption->OptionName->addItem("HideMilkyWay");
631     argChangeViewOption->OptionName->addItem("HideCNames");
632     argChangeViewOption->OptionName->addItem("HideCLines");
633     argChangeViewOption->OptionName->addItem("HideCBounds");
634     argChangeViewOption->OptionName->addItem("HideGrid");
635 
636     opsSkymap = new QTreeWidgetItem(otv->optionsList(), QStringList(i18n("Skymap Options")));
637     fields << "UseAltAz" << i18n("Use Horizontal coordinates? (otherwise, use Equatorial)") << i18n("bool");
638     new QTreeWidgetItem(opsSkymap, fields);
639     fields.clear();
640     fields << "ZoomFactor" << i18n("Set the Zoom Factor") << i18n("double");
641     new QTreeWidgetItem(opsSkymap, fields);
642     fields.clear();
643     fields << "FOVName" << i18n("Select angular size for the FOV symbol (in arcmin)") << i18n("double");
644     new QTreeWidgetItem(opsSkymap, fields);
645     fields.clear();
646     fields << "FOVShape" << i18n("Select shape for the FOV symbol (0=Square, 1=Circle, 2=Crosshairs, 4=Bullseye)")
647            << i18n("int");
648     new QTreeWidgetItem(opsSkymap, fields);
649     fields.clear();
650     fields << "FOVColor" << i18n("Select color for the FOV symbol") << i18n("string");
651     new QTreeWidgetItem(opsSkymap, fields);
652     fields.clear();
653     fields << "UseAnimatedSlewing" << i18n("Use animated slewing? (otherwise, \"snap\" to new focus)") << i18n("bool");
654     new QTreeWidgetItem(opsSkymap, fields);
655     fields.clear();
656     fields << "UseRefraction" << i18n("Correct for atmospheric refraction?") << i18n("bool");
657     new QTreeWidgetItem(opsSkymap, fields);
658     fields.clear();
659     fields << "UseAutoLabel" << i18n("Automatically attach name label to centered object?") << i18n("bool");
660     new QTreeWidgetItem(opsSkymap, fields);
661     fields.clear();
662     fields << "UseHoverLabel" << i18n("Attach temporary name label when hovering mouse over an object?")
663            << i18n("bool");
664     new QTreeWidgetItem(opsSkymap, fields);
665     fields.clear();
666     fields << "UseAutoTrail" << i18n("Automatically add trail to centered solar system body?") << i18n("bool");
667     new QTreeWidgetItem(opsSkymap, fields);
668     fields.clear();
669     fields << "FadePlanetTrails" << i18n("Planet trails fade to sky color? (otherwise color is constant)")
670            << i18n("bool");
671     new QTreeWidgetItem(opsSkymap, fields);
672     fields.clear();
673 
674     argChangeViewOption->OptionName->addItem("UseAltAz");
675     argChangeViewOption->OptionName->addItem("ZoomFactor");
676     argChangeViewOption->OptionName->addItem("FOVName");
677     argChangeViewOption->OptionName->addItem("FOVSize");
678     argChangeViewOption->OptionName->addItem("FOVShape");
679     argChangeViewOption->OptionName->addItem("FOVColor");
680     argChangeViewOption->OptionName->addItem("UseRefraction");
681     argChangeViewOption->OptionName->addItem("UseAutoLabel");
682     argChangeViewOption->OptionName->addItem("UseHoverLabel");
683     argChangeViewOption->OptionName->addItem("UseAutoTrail");
684     argChangeViewOption->OptionName->addItem("AnimateSlewing");
685     argChangeViewOption->OptionName->addItem("FadePlanetTrails");
686 
687     opsLimit = new QTreeWidgetItem(otv->optionsList(), QStringList(i18n("Limits")));
688     /*
689     fields << "magLimitDrawStar" << i18n( "magnitude of faintest star drawn on map when zoomed in" ) << i18n( "double" );
690     new QTreeWidgetItem( opsLimit, fields );
691     fields.clear();
692     fields << "magLimitDrawStarZoomOut" << i18n( "magnitude of faintest star drawn on map when zoomed out" ) << i18n( "double" );
693     new QTreeWidgetItem( opsLimit, fields );
694     fields.clear();
695     */
696 
697     // TODO: We have disabled the following two features. Enable them when feasible...
698     /*
699     fields << "magLimitDrawDeepSky" << i18n( "magnitude of faintest nonstellar object drawn on map when zoomed in" ) << i18n( "double" );
700     new QTreeWidgetItem( opsLimit, fields );
701     fields.clear();
702     fields << "magLimitDrawDeepSkyZoomOut" << i18n( "magnitude of faintest nonstellar object drawn on map when zoomed out" ) << i18n( "double" );
703     new QTreeWidgetItem( opsLimit, fields );
704     fields.clear();
705     */
706 
707     //FIXME: This description is incorrect! Fix after strings freeze
708     fields << "starLabelDensity" << i18n("magnitude of faintest star labeled on map") << i18n("double");
709     new QTreeWidgetItem(opsLimit, fields);
710     fields.clear();
711     fields << "magLimitHideStar" << i18n("magnitude of brightest star hidden while slewing") << i18n("double");
712     new QTreeWidgetItem(opsLimit, fields);
713     fields.clear();
714     fields << "magLimitAsteroid" << i18n("magnitude of faintest asteroid drawn on map") << i18n("double");
715     new QTreeWidgetItem(opsLimit, fields);
716     fields.clear();
717     //FIXME: This description is incorrect! Fix after strings freeze
718     fields << "asteroidLabelDensity" << i18n("magnitude of faintest asteroid labeled on map") << i18n("double");
719     new QTreeWidgetItem(opsLimit, fields);
720     fields.clear();
721     fields << "maxRadCometName" << i18n("comets nearer to the Sun than this (in AU) are labeled on map")
722            << i18n("double");
723     new QTreeWidgetItem(opsLimit, fields);
724     fields.clear();
725 
726     //    argChangeViewOption->OptionName->addItem( "magLimitDrawStar" );
727     //    argChangeViewOption->OptionName->addItem( "magLimitDrawStarZoomOut" );
728     argChangeViewOption->OptionName->addItem("magLimitDrawDeepSky");
729     argChangeViewOption->OptionName->addItem("magLimitDrawDeepSkyZoomOut");
730     argChangeViewOption->OptionName->addItem("starLabelDensity");
731     argChangeViewOption->OptionName->addItem("magLimitHideStar");
732     argChangeViewOption->OptionName->addItem("magLimitAsteroid");
733     argChangeViewOption->OptionName->addItem("asteroidLabelDensity");
734     argChangeViewOption->OptionName->addItem("maxRadCometName");
735 
736     //init the list of color names and values
737     for (unsigned int i = 0; i < KStarsData::Instance()->colorScheme()->numberOfColors(); ++i)
738     {
739         argSetColor->ColorName->addItem(KStarsData::Instance()->colorScheme()->nameAt(i));
740     }
741 
742     //init list of color scheme names
743     argLoadColorScheme->SchemeList->addItem(i18nc("use default color scheme", "Default Colors"));
744     argLoadColorScheme->SchemeList->addItem(i18nc("use 'star chart' color scheme", "Star Chart"));
745     argLoadColorScheme->SchemeList->addItem(i18nc("use 'night vision' color scheme", "Night Vision"));
746     argLoadColorScheme->SchemeList->addItem(i18nc("use 'moonless night' color scheme", "Moonless Night"));
747 
748     QFile file;
749     QString line;
750     //determine filename in local user KDE directory tree.
751     file.setFileName(KSPaths::locate(QStandardPaths::AppDataLocation, "colors.dat"));
752     if (file.open(QIODevice::ReadOnly))
753     {
754         QTextStream stream(&file);
755 
756         while (!stream.atEnd())
757         {
758             line = stream.readLine();
759             argLoadColorScheme->SchemeList->addItem(line.left(line.indexOf(':')));
760         }
761         file.close();
762     }
763 }
764 
765 //Slots defined in ScriptBuilderUI
slotNew()766 void ScriptBuilder::slotNew()
767 {
768     saveWarning();
769     if (!UnsavedChanges)
770     {
771         ScriptList.clear();
772         sb->ScriptListBox->clear();
773         sb->ArgStack->setCurrentWidget(argBlank);
774 
775         sb->CopyButton->setEnabled(false);
776         sb->RemoveButton->setEnabled(false);
777         sb->RunButton->setEnabled(false);
778         sb->SaveAsButton->setEnabled(false);
779 
780         currentFileURL.clear();
781         currentScriptName.clear();
782     }
783 }
784 
slotOpen()785 void ScriptBuilder::slotOpen()
786 {
787     saveWarning();
788 
789     QString fname;
790     QTemporaryFile tmpfile;
791     tmpfile.open();
792 
793     if (!UnsavedChanges)
794     {
795         currentFileURL = QFileDialog::getOpenFileUrl(
796                              KStars::Instance(), QString(), QUrl(currentDir),
797                              "*.kstars|" + i18nc("Filter by file type: KStars Scripts.", "KStars Scripts (*.kstars)"));
798 
799         if (currentFileURL.isValid())
800         {
801             currentDir = currentFileURL.toLocalFile();
802 
803             ScriptList.clear();
804             sb->ScriptListBox->clear();
805             sb->ArgStack->setCurrentWidget(argBlank);
806 
807             if (currentFileURL.isLocalFile())
808             {
809                 fname = currentFileURL.toLocalFile();
810             }
811             else
812             {
813                 fname = tmpfile.fileName();
814                 if (KIO::copy(currentFileURL, QUrl(fname))->exec() == false)
815                     //if ( ! KIO::NetAccess::download( currentFileURL, fname, (QWidget*) 0 ) )
816                     KSNotification::sorry(i18n("Could not download remote file."), i18n("Download Error"));
817             }
818 
819             QFile f(fname);
820             if (!f.open(QIODevice::ReadOnly))
821             {
822                 KSNotification::sorry(i18n("Could not open file %1.", f.fileName()), i18n("Could Not Open File"));
823                 currentFileURL.clear();
824                 return;
825             }
826 
827             QTextStream istream(&f);
828             readScript(istream);
829 
830             f.close();
831         }
832         else if (!currentFileURL.url().isEmpty())
833         {
834             KSNotification::sorry(i18n("Invalid URL: %1", currentFileURL.url()), i18n("Invalid URL"));
835             currentFileURL.clear();
836         }
837     }
838 }
839 
slotSave()840 void ScriptBuilder::slotSave()
841 {
842     QString fname;
843     QTemporaryFile tmpfile;
844     tmpfile.open();
845 
846     if (currentScriptName.isEmpty())
847     {
848         //Get Script Name and Author info
849         if (snd->exec() == QDialog::Accepted)
850         {
851             currentScriptName = snd->scriptName();
852             currentAuthor     = snd->authorName();
853         }
854         else
855         {
856             return;
857         }
858     }
859 
860     bool newFilename = false;
861     if (currentFileURL.isEmpty())
862     {
863         currentFileURL = QFileDialog::getSaveFileUrl(
864                              KStars::Instance(), QString(), QUrl(currentDir),
865                              "*.kstars|" + i18nc("Filter by file type: KStars Scripts.", "KStars Scripts (*.kstars)"));
866         newFilename = true;
867     }
868 
869     if (currentFileURL.isValid())
870     {
871         currentDir = currentFileURL.toLocalFile();
872 
873         if (currentFileURL.isLocalFile())
874         {
875             fname = currentFileURL.toLocalFile();
876 
877             //Warn user if file exists
878             if (newFilename == true && QFile::exists(currentFileURL.toLocalFile()))
879             {
880                 int r = KMessageBox::warningContinueCancel(static_cast<QWidget *>(parent()),
881                         i18n("A file named \"%1\" already exists. "
882                              "Overwrite it?",
883                              currentFileURL.fileName()),
884                         i18n("Overwrite File?"), KStandardGuiItem::overwrite());
885 
886                 if (r == KMessageBox::Cancel)
887                     return;
888             }
889         }
890         else
891         {
892             fname = tmpfile.fileName();
893         }
894 
895         if (fname.right(7).toLower() != ".kstars")
896             fname += ".kstars";
897 
898         QFile f(fname);
899         if (!f.open(QIODevice::WriteOnly))
900         {
901             QString message = i18n("Could not open file %1.", f.fileName());
902             KSNotification::sorry(message, i18n("Could Not Open File"));
903             currentFileURL.clear();
904             return;
905         }
906 
907         QTextStream ostream(&f);
908         writeScript(ostream);
909         f.close();
910 
911 #ifndef _WIN32
912         //set rwx for owner, rx for group, rx for other
913         chmod(fname.toLatin1(), S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
914 #endif
915 
916         if (tmpfile.fileName() == fname)
917         {
918             //need to upload to remote location
919             //if ( ! KIO::NetAccess::upload( tmpfile.fileName(), currentFileURL, (QWidget*) 0 ) )
920             if (KIO::storedHttpPost(&tmpfile, currentFileURL)->exec() == false)
921             {
922                 QString message = i18n("Could not upload image to remote location: %1", currentFileURL.url());
923                 KSNotification::sorry(message, i18n("Could not upload file"));
924             }
925         }
926 
927         setUnsavedChanges(false);
928     }
929     else
930     {
931         QString message = i18n("Invalid URL: %1", currentFileURL.url());
932         KSNotification::sorry(message, i18n("Invalid URL"));
933         currentFileURL.clear();
934     }
935 }
936 
slotSaveAs()937 void ScriptBuilder::slotSaveAs()
938 {
939     currentFileURL.clear();
940     currentScriptName.clear();
941     slotSave();
942 }
943 
saveWarning()944 void ScriptBuilder::saveWarning()
945 {
946     if (UnsavedChanges)
947     {
948         QString caption = i18n("Save Changes to Script?");
949         QString message = i18n("The current script has unsaved changes.  Would you like to save before closing it?");
950         int ans =
951             KMessageBox::warningYesNoCancel(nullptr, message, caption, KStandardGuiItem::save(), KStandardGuiItem::discard());
952         if (ans == KMessageBox::Yes)
953         {
954             slotSave();
955             setUnsavedChanges(false);
956         }
957         else if (ans == KMessageBox::No)
958         {
959             setUnsavedChanges(false);
960         }
961 
962         //Do nothing if 'cancel' selected
963     }
964 }
965 
slotRunScript()966 void ScriptBuilder::slotRunScript()
967 {
968     //hide window while script runs
969     // If this is uncommented, the program hangs before the script is executed.  Why?
970     //	hide();
971 
972     //Save current script to a temporary file, then execute that file.
973     //For some reason, I can't use KTempFile here!  If I do, then the temporary script
974     //is not executable.  Bizarre...
975     //KTempFile tmpfile;
976     //QString fname = tmpfile.name();
977     QString fname = QDir::tempPath() + QDir::separator() + "kstars-tempscript";
978 
979     QFile f(fname);
980     if (f.exists())
981         f.remove();
982     if (!f.open(QIODevice::WriteOnly))
983     {
984         QString message = i18n("Could not open file %1.", f.fileName());
985         KSNotification::sorry(message, i18n("Could Not Open File"));
986         currentFileURL.clear();
987         return;
988     }
989 
990     QTextStream ostream(&f);
991     writeScript(ostream);
992     f.close();
993 
994 #ifndef _WIN32
995     //set rwx for owner, rx for group, rx for other
996     chmod(QFile::encodeName(f.fileName()), S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
997 #endif
998 
999     QProcess p;
1000 #ifdef Q_OS_OSX
1001     QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
1002     QString path            = env.value("PATH", "");
1003     env.insert("PATH", "/usr/local/bin:" + QCoreApplication::applicationDirPath() + ':' + path);
1004     p.setProcessEnvironment(env);
1005 #endif
1006     p.start(f.fileName());
1007 
1008     if (!p.waitForStarted())
1009         qDebug() << "Process did not start.";
1010 
1011     while (!p.waitForFinished(10))
1012     {
1013         qApp->processEvents(); //otherwise tempfile may get deleted before script completes.
1014         if (p.state() != QProcess::Running)
1015             break;
1016     }
1017     //delete temp file
1018     if (f.exists())
1019         f.remove();
1020 
1021     //uncomment if 'hide()' is uncommented...
1022     //	show();
1023 }
1024 
1025 /*
1026   This can't work anymore and is also not portable in any way :(
1027 */
writeScript(QTextStream & ostream)1028 void ScriptBuilder::writeScript(QTextStream &ostream)
1029 {
1030     // FIXME Without --print-reply, the dbus-send doesn't do anything, why??
1031     QString dbus_call    = "dbus-send --dest=org.kde.kstars --print-reply ";
1032     QString main_method  = "/KStars org.kde.kstars.";
1033     QString clock_method = "/KStars/SimClock org.kde.kstars.SimClock.";
1034 
1035     //Write script header
1036     ostream << "#!/bin/bash\n";
1037     ostream << "#KStars DBus script: " << currentScriptName << '\n';
1038     ostream << "#by " << currentAuthor << '\n';
1039     ostream << "#last modified: " << KStarsDateTime::currentDateTime().toString(Qt::ISODate) << '\n';
1040     ostream << "#\n";
1041 
1042     foreach (ScriptFunction *sf, ScriptList)
1043     {
1044         if (!sf->valid())
1045             continue;
1046 
1047         if (sf->isClockFunction())
1048         {
1049             ostream << dbus_call << clock_method << sf->scriptLine() << '\n';
1050         }
1051         else
1052         {
1053             ostream << dbus_call << main_method << sf->scriptLine() << '\n';
1054         }
1055     }
1056 
1057     //Write script footer
1058     ostream << "##\n";
1059     ostream.flush();
1060 }
1061 
readScript(QTextStream & istream)1062 void ScriptBuilder::readScript(QTextStream &istream)
1063 {
1064     QString line;
1065     QString service_name = "org.kde.kstars.";
1066     QString fn_name;
1067 
1068     while (!istream.atEnd())
1069     {
1070         line = istream.readLine();
1071 
1072         //look for name of script
1073         if (line.contains("#KStars DBus script: "))
1074             currentScriptName = line.mid(21).trimmed();
1075 
1076         //look for author of scriptbuilder
1077         if (line.contains("#by "))
1078             currentAuthor = line.mid(4).trimmed();
1079 
1080         //Actual script functions
1081         if (line.left(4) == "dbus")
1082         {
1083             //is ClockFunction?
1084             if (line.contains("SimClock"))
1085             {
1086                 service_name += "SimClock.";
1087             }
1088 
1089             //remove leading dbus prefix
1090             line = line.mid(line.lastIndexOf(service_name) + service_name.count());
1091 
1092             fn_name = line.left(line.indexOf(' '));
1093 
1094             line = line.mid(line.indexOf(' ') + 1);
1095 
1096             //construct a stringlist that is fcn name and its arg name/value pairs
1097             QStringList fn;
1098 
1099             // If the function lacks any arguments, do not attempt to split
1100             //            if (fn_name != line)
1101             //                fn = line.split(' ');
1102 
1103             if (parseFunction(fn_name, line))
1104             {
1105                 sb->ScriptListBox->addItem(ScriptList.last()->name());
1106                 // Initially, any read script is valid!
1107                 ScriptList.last()->setValid(true);
1108             }
1109             else
1110                 qWarning() << i18n("Could not parse script.  Line was: %1", line);
1111 
1112         } // end if left(4) == "dcop"
1113     }     // end while !atEnd()
1114 
1115     //Select first item in sb->ScriptListBox
1116     if (sb->ScriptListBox->count())
1117     {
1118         sb->ScriptListBox->setCurrentItem(nullptr);
1119         slotArgWidget();
1120     }
1121 }
1122 
parseFunction(const QString & fn_name,const QString & fn_args)1123 bool ScriptBuilder::parseFunction(const QString &fn_name, const QString &fn_args)
1124 {
1125     // clean up the string list first if needed
1126     // We need to perform this in case we havea quoted string "NGC 3000" because this will counted
1127     // as two arguments, and it should be counted as one.
1128     //    bool foundQuote(false), quoteProcessed(false);
1129     //    QString cur, arg;
1130     //    QStringList::iterator it;
1131 
1132     //    for (it = fn.begin(); it != fn.end(); ++it)
1133     //    {
1134     //        cur = (*it);
1135 
1136     //        cur = cur.mid(cur.indexOf(":") + 1).remove('\'');
1137 
1138     //        (*it) = cur;
1139 
1140     //        if (cur.startsWith('\"'))
1141     //        {
1142     //            arg += cur.rightRef(cur.length() - 1);
1143     //            arg += ' ';
1144     //            foundQuote     = true;
1145     //            quoteProcessed = true;
1146     //        }
1147     //        else if (cur.endsWith('\"'))
1148     //        {
1149     //            arg += cur.leftRef(cur.length() - 1);
1150     //            arg += '\'';
1151     //            foundQuote = false;
1152     //        }
1153     //        else if (foundQuote)
1154     //        {
1155     //            arg += cur;
1156     //            arg += ' ';
1157     //        }
1158     //        else
1159     //        {
1160     //            arg += cur;
1161     //            arg += '\'';
1162     //        }
1163     //    }
1164 
1165     //    if (quoteProcessed)
1166     //        fn = arg.split(' ', QString::SkipEmptyParts);
1167 
1168     QRegularExpression re("(?<=:)[^:\\s]*");
1169     QRegularExpressionMatchIterator i = re.globalMatch(fn_args);
1170     QStringList fn;
1171     while (i.hasNext())
1172     {
1173         QRegularExpressionMatch match = i.next();
1174         fn << match.captured(0).remove("\"");
1175     };
1176 
1177     //loop over known functions to find a name match
1178     for (auto &sf : KStarsFunctionList)
1179     {
1180         if (fn_name == sf->name())
1181         {
1182             //            if (fn_name == "setGeoLocation")
1183             //            {
1184             //                ScriptList.append(new ScriptFunction(sf));
1185             //                ScriptList.last()->setArg(0, fn[0]);
1186             //                ScriptList.last()->setArg(1, fn[1]);
1187             //                ScriptList.last()->setArg(2, fn[2]);
1188             //            }
1189             //            else if (fn.count() != sf->numArgs())
1190             //                return false;
1191 
1192             ScriptList.append(new ScriptFunction(sf));
1193 
1194             for (int i = 0; i < sf->numArgs(); ++i)
1195                 ScriptList.last()->setArg(i, fn[i]);
1196 
1197             return true;
1198         }
1199 
1200         foreach (ScriptFunction *sf, SimClockFunctionList)
1201         {
1202             if (fn_name == sf->name())
1203             {
1204                 if (fn.count() != sf->numArgs())
1205                     return false;
1206 
1207                 ScriptList.append(new ScriptFunction(sf));
1208 
1209                 for (int i = 0; i < sf->numArgs(); ++i)
1210                     ScriptList.last()->setArg(i, fn[i]);
1211 
1212                 return true;
1213             }
1214         }
1215     }
1216 
1217     //if we get here, no function-name match was found
1218     return false;
1219 }
1220 
setUnsavedChanges(bool b)1221 void ScriptBuilder::setUnsavedChanges(bool b)
1222 {
1223     if (checkForChanges)
1224     {
1225         UnsavedChanges = b;
1226         sb->SaveButton->setEnabled(b);
1227     }
1228 }
1229 
slotCopyFunction()1230 void ScriptBuilder::slotCopyFunction()
1231 {
1232     if (!UnsavedChanges)
1233         setUnsavedChanges(true);
1234 
1235     int Pos = sb->ScriptListBox->currentRow() + 1;
1236     ScriptList.insert(Pos, new ScriptFunction(ScriptList[Pos - 1]));
1237     //copy ArgVals
1238     for (int i = 0; i < ScriptList[Pos - 1]->numArgs(); ++i)
1239         ScriptList[Pos]->setArg(i, ScriptList[Pos - 1]->argVal(i));
1240 
1241     sb->ScriptListBox->insertItem(Pos, ScriptList[Pos]->name());
1242     //sb->ScriptListBox->setSelected( Pos, true );
1243     sb->ScriptListBox->setCurrentRow(Pos);
1244     slotArgWidget();
1245 }
1246 
slotRemoveFunction()1247 void ScriptBuilder::slotRemoveFunction()
1248 {
1249     setUnsavedChanges(true);
1250 
1251     int Pos = sb->ScriptListBox->currentRow();
1252     ScriptList.removeAt(Pos);
1253     sb->ScriptListBox->takeItem(Pos);
1254     if (sb->ScriptListBox->count() == 0)
1255     {
1256         sb->ArgStack->setCurrentWidget(argBlank);
1257         sb->CopyButton->setEnabled(false);
1258         sb->RemoveButton->setEnabled(false);
1259         sb->RunButton->setEnabled(false);
1260         sb->SaveAsButton->setEnabled(false);
1261     }
1262     else
1263     {
1264         //sb->ScriptListBox->setSelected( Pos, true );
1265         if (Pos == sb->ScriptListBox->count())
1266         {
1267             Pos = Pos - 1;
1268         }
1269         sb->ScriptListBox->setCurrentRow(Pos);
1270     }
1271     slotArgWidget();
1272 }
1273 
slotAddFunction()1274 void ScriptBuilder::slotAddFunction()
1275 {
1276     ScriptFunction *found        = nullptr;
1277     QTreeWidgetItem *currentItem = sb->FunctionTree->currentItem();
1278 
1279     if (currentItem == nullptr || currentItem->parent() == nullptr)
1280         return;
1281 
1282     for (auto &sc : KStarsFunctionList)
1283     {
1284         if (sc->prototype() == currentItem->text(0))
1285         {
1286             found = sc;
1287             break;
1288         }
1289     }
1290 
1291     for (auto &sc : SimClockFunctionList)
1292     {
1293         if (sc->prototype() == currentItem->text(0))
1294         {
1295             found = sc;
1296             break;
1297         }
1298     }
1299 
1300     if (found == nullptr)
1301         return;
1302 
1303     setUnsavedChanges(true);
1304 
1305     int Pos = sb->ScriptListBox->currentRow() + 1;
1306 
1307     ScriptList.insert(Pos, new ScriptFunction(found));
1308     sb->ScriptListBox->insertItem(Pos, ScriptList[Pos]->name());
1309     sb->ScriptListBox->setCurrentRow(Pos);
1310     slotArgWidget();
1311 }
1312 
slotMoveFunctionUp()1313 void ScriptBuilder::slotMoveFunctionUp()
1314 {
1315     if (sb->ScriptListBox->currentRow() > 0)
1316     {
1317         setUnsavedChanges(true);
1318 
1319         //QString t = sb->ScriptListBox->currentItem()->text();
1320         QString t      = sb->ScriptListBox->currentItem()->text();
1321         unsigned int n = sb->ScriptListBox->currentRow();
1322 
1323         ScriptFunction *tmp = ScriptList.takeAt(n);
1324         ScriptList.insert(n - 1, tmp);
1325 
1326         sb->ScriptListBox->takeItem(n);
1327         sb->ScriptListBox->insertItem(n - 1, t);
1328         sb->ScriptListBox->setCurrentRow(n - 1);
1329         slotArgWidget();
1330     }
1331 }
1332 
slotMoveFunctionDown()1333 void ScriptBuilder::slotMoveFunctionDown()
1334 {
1335     if (sb->ScriptListBox->currentRow() > -1 && sb->ScriptListBox->currentRow() < ((int)sb->ScriptListBox->count()) - 1)
1336     {
1337         setUnsavedChanges(true);
1338 
1339         QString t      = sb->ScriptListBox->currentItem()->text();
1340         unsigned int n = sb->ScriptListBox->currentRow();
1341 
1342         ScriptFunction *tmp = ScriptList.takeAt(n);
1343         ScriptList.insert(n + 1, tmp);
1344 
1345         sb->ScriptListBox->takeItem(n);
1346         sb->ScriptListBox->insertItem(n + 1, t);
1347         sb->ScriptListBox->setCurrentRow(n + 1);
1348         slotArgWidget();
1349     }
1350 }
1351 
slotArgWidget()1352 void ScriptBuilder::slotArgWidget()
1353 {
1354     //First, setEnabled on buttons that act on the selected script function
1355     if (sb->ScriptListBox->currentRow() == -1) //no selection
1356     {
1357         sb->CopyButton->setEnabled(false);
1358         sb->RemoveButton->setEnabled(false);
1359         sb->UpButton->setEnabled(false);
1360         sb->DownButton->setEnabled(false);
1361     }
1362     else if (sb->ScriptListBox->count() == 1) //only one item, so disable up/down buttons
1363     {
1364         sb->CopyButton->setEnabled(true);
1365         sb->RemoveButton->setEnabled(true);
1366         sb->UpButton->setEnabled(false);
1367         sb->DownButton->setEnabled(false);
1368     }
1369     else if (sb->ScriptListBox->currentRow() == 0) //first item selected
1370     {
1371         sb->CopyButton->setEnabled(true);
1372         sb->RemoveButton->setEnabled(true);
1373         sb->UpButton->setEnabled(false);
1374         sb->DownButton->setEnabled(true);
1375     }
1376     else if (sb->ScriptListBox->currentRow() == ((int)sb->ScriptListBox->count()) - 1) //last item selected
1377     {
1378         sb->CopyButton->setEnabled(true);
1379         sb->RemoveButton->setEnabled(true);
1380         sb->UpButton->setEnabled(true);
1381         sb->DownButton->setEnabled(false);
1382     }
1383     else //other item selected
1384     {
1385         sb->CopyButton->setEnabled(true);
1386         sb->RemoveButton->setEnabled(true);
1387         sb->UpButton->setEnabled(true);
1388         sb->DownButton->setEnabled(true);
1389     }
1390 
1391     //RunButton and SaveAs button enabled when script not empty.
1392     if (sb->ScriptListBox->count())
1393     {
1394         sb->RunButton->setEnabled(true);
1395         sb->SaveAsButton->setEnabled(true);
1396     }
1397     else
1398     {
1399         sb->RunButton->setEnabled(false);
1400         sb->SaveAsButton->setEnabled(false);
1401         setUnsavedChanges(false);
1402     }
1403 
1404     //Display the function's arguments widget
1405     if (sb->ScriptListBox->currentRow() > -1 && sb->ScriptListBox->currentRow() < ((int)sb->ScriptListBox->count()))
1406     {
1407         unsigned int n     = sb->ScriptListBox->currentRow();
1408         ScriptFunction *sf = ScriptList.at(n);
1409 
1410         checkForChanges = false; //Don't signal unsaved changes
1411 
1412         if (sf->name() == "lookTowards")
1413         {
1414             sb->ArgStack->setCurrentWidget(argLookToward);
1415             QString s = sf->argVal(0);
1416             argLookToward->FocusEdit->setEditText(s);
1417         }
1418         else if (sf->name() == "addLabel" || sf->name() == "removeLabel" || sf->name() == "addTrail" ||
1419                  sf->name() == "removeTrail")
1420         {
1421             sb->ArgStack->setCurrentWidget(argFindObject);
1422             QString s = sf->argVal(0);
1423             argFindObject->NameEdit->setText(s);
1424         }
1425         else if (sf->name() == "setRaDec")
1426         {
1427             bool ok(false);
1428             double r(0.0), d(0.0);
1429             dms ra(0.0);
1430 
1431             sb->ArgStack->setCurrentWidget(argSetRaDec);
1432 
1433             ok = !sf->argVal(0).isEmpty();
1434             if (ok)
1435                 r = sf->argVal(0).toDouble(&ok);
1436             else
1437                 argSetRaDec->RABox->clear();
1438             if (ok)
1439             {
1440                 ra.setH(r);
1441                 argSetRaDec->RABox->showInHours(ra);
1442             }
1443 
1444             ok = !sf->argVal(1).isEmpty();
1445             if (ok)
1446                 d = sf->argVal(1).toDouble(&ok);
1447             else
1448                 argSetRaDec->DecBox->clear();
1449             if (ok)
1450                 argSetRaDec->DecBox->showInDegrees(dms(d));
1451         }
1452         else if (sf->name() == "setAltAz")
1453         {
1454             bool ok(false);
1455             double x(0.0), y(0.0);
1456 
1457             sb->ArgStack->setCurrentWidget(argSetAltAz);
1458 
1459             ok = !sf->argVal(0).isEmpty();
1460             if (ok)
1461                 y = sf->argVal(0).toDouble(&ok);
1462             else
1463                 argSetAltAz->AzBox->clear();
1464             if (ok)
1465                 argSetAltAz->AltBox->showInDegrees(dms(y));
1466             else
1467                 argSetAltAz->AltBox->clear();
1468 
1469             ok = !sf->argVal(1).isEmpty();
1470             x  = sf->argVal(1).toDouble(&ok);
1471             if (ok)
1472                 argSetAltAz->AzBox->showInDegrees(dms(x));
1473         }
1474         else if (sf->name() == "zoomIn")
1475         {
1476             sb->ArgStack->setCurrentWidget(argBlank);
1477             //no Args
1478         }
1479         else if (sf->name() == "zoomOut")
1480         {
1481             sb->ArgStack->setCurrentWidget(argBlank);
1482             //no Args
1483         }
1484         else if (sf->name() == "defaultZoom")
1485         {
1486             sb->ArgStack->setCurrentWidget(argBlank);
1487             //no Args
1488         }
1489         else if (sf->name() == "zoom")
1490         {
1491             sb->ArgStack->setCurrentWidget(argZoom);
1492             bool ok(false);
1493             /*double z = */ sf->argVal(0).toDouble(&ok);
1494             if (ok)
1495                 argZoom->ZoomBox->setText(sf->argVal(0));
1496             else
1497                 argZoom->ZoomBox->setText("2000.");
1498         }
1499         else if (sf->name() == "exportImage")
1500         {
1501             sb->ArgStack->setCurrentWidget(argExportImage);
1502             argExportImage->ExportFileName->setUrl(QUrl::fromUserInput(sf->argVal(0)));
1503             bool ok(false);
1504             int w = 0, h = 0;
1505             w = sf->argVal(1).toInt(&ok);
1506             if (ok)
1507                 h = sf->argVal(2).toInt(&ok);
1508             if (ok)
1509             {
1510                 argExportImage->ExportWidth->setValue(w);
1511                 argExportImage->ExportHeight->setValue(h);
1512             }
1513             else
1514             {
1515                 argExportImage->ExportWidth->setValue(SkyMap::Instance()->width());
1516                 argExportImage->ExportHeight->setValue(SkyMap::Instance()->height());
1517             }
1518         }
1519         else if (sf->name() == "printImage")
1520         {
1521             if (sf->argVal(0) == i18n("true"))
1522                 argPrintImage->UsePrintDialog->setChecked(true);
1523             else
1524                 argPrintImage->UsePrintDialog->setChecked(false);
1525             if (sf->argVal(1) == i18n("true"))
1526                 argPrintImage->UseChartColors->setChecked(true);
1527             else
1528                 argPrintImage->UseChartColors->setChecked(false);
1529         }
1530         else if (sf->name() == "setLocalTime")
1531         {
1532             sb->ArgStack->setCurrentWidget(argSetLocalTime);
1533             bool ok(false);
1534             int year = 0, month = 0, day = 0, hour = 0, min = 0, sec = 0;
1535 
1536             year = sf->argVal(0).toInt(&ok);
1537             if (ok)
1538                 month = sf->argVal(1).toInt(&ok);
1539             if (ok)
1540                 day = sf->argVal(2).toInt(&ok);
1541             if (ok)
1542                 argSetLocalTime->DateWidget->setDate(QDate(year, month, day));
1543             else
1544                 argSetLocalTime->DateWidget->setDate(QDate::currentDate());
1545 
1546             hour = sf->argVal(3).toInt(&ok);
1547             if (sf->argVal(3).isEmpty())
1548                 ok = false;
1549             if (ok)
1550                 min = sf->argVal(4).toInt(&ok);
1551             if (ok)
1552                 sec = sf->argVal(5).toInt(&ok);
1553             if (ok)
1554                 argSetLocalTime->TimeBox->setTime(QTime(hour, min, sec));
1555             else
1556                 argSetLocalTime->TimeBox->setTime(QTime(QTime::currentTime()));
1557         }
1558         else if (sf->name() == "waitFor")
1559         {
1560             sb->ArgStack->setCurrentWidget(argWaitFor);
1561             bool ok(false);
1562             int sec = sf->argVal(0).toInt(&ok);
1563             if (ok)
1564                 argWaitFor->DelayBox->setValue(sec);
1565             else
1566                 argWaitFor->DelayBox->setValue(0);
1567         }
1568         else if (sf->name() == "waitForKey")
1569         {
1570             sb->ArgStack->setCurrentWidget(argWaitForKey);
1571             if (sf->argVal(0).length() == 1 || sf->argVal(0).toLower() == "space")
1572                 argWaitForKey->WaitKeyEdit->setText(sf->argVal(0));
1573             else
1574                 argWaitForKey->WaitKeyEdit->setText(QString());
1575         }
1576         else if (sf->name() == "setTracking")
1577         {
1578             sb->ArgStack->setCurrentWidget(argSetTracking);
1579             if (sf->argVal(0) == i18n("true"))
1580                 argSetTracking->CheckTrack->setChecked(true);
1581             else
1582                 argSetTracking->CheckTrack->setChecked(false);
1583         }
1584         else if (sf->name() == "changeViewOption")
1585         {
1586             sb->ArgStack->setCurrentWidget(argChangeViewOption);
1587             argChangeViewOption->OptionName->setCurrentIndex(argChangeViewOption->OptionName->findText(sf->argVal(0)));
1588             argChangeViewOption->OptionValue->setText(sf->argVal(1));
1589         }
1590         else if (sf->name() == "setGeoLocation")
1591         {
1592             sb->ArgStack->setCurrentWidget(argSetGeoLocation);
1593             argSetGeoLocation->CityName->setText(sf->argVal(0));
1594             argSetGeoLocation->ProvinceName->setText(sf->argVal(1));
1595             argSetGeoLocation->CountryName->setText(sf->argVal(2));
1596         }
1597         else if (sf->name() == "setColor")
1598         {
1599             sb->ArgStack->setCurrentWidget(argSetColor);
1600             if (sf->argVal(0).isEmpty())
1601                 sf->setArg(0, "SkyColor"); //initialize default value
1602             argSetColor->ColorName->setCurrentIndex(
1603                 argSetColor->ColorName->findText(KStarsData::Instance()->colorScheme()->nameFromKey(sf->argVal(0))));
1604             argSetColor->ColorValue->setColor(QColor(sf->argVal(1).remove('\\')));
1605         }
1606         else if (sf->name() == "loadColorScheme")
1607         {
1608             sb->ArgStack->setCurrentWidget(argLoadColorScheme);
1609             argLoadColorScheme->SchemeList->setCurrentItem(
1610                 argLoadColorScheme->SchemeList->findItems(sf->argVal(0).remove('\"'), Qt::MatchExactly).at(0));
1611         }
1612         else if (sf->name() == "stop")
1613         {
1614             sb->ArgStack->setCurrentWidget(argBlank);
1615             //no Args
1616         }
1617         else if (sf->name() == "start")
1618         {
1619             sb->ArgStack->setCurrentWidget(argBlank);
1620             //no Args
1621         }
1622         else if (sf->name() == "setClockScale")
1623         {
1624             sb->ArgStack->setCurrentWidget(argTimeScale);
1625             bool ok(false);
1626             double ts = sf->argVal(0).toDouble(&ok);
1627             if (ok)
1628                 argTimeScale->TimeScale->tsbox()->changeScale(float(ts));
1629             else
1630                 argTimeScale->TimeScale->tsbox()->changeScale(0.0);
1631         }
1632 
1633         checkForChanges = true; //signal unsaved changes if the argument widgets are changed
1634     }
1635 }
1636 
slotShowDoc()1637 void ScriptBuilder::slotShowDoc()
1638 {
1639     ScriptFunction *found        = nullptr;
1640     QTreeWidgetItem *currentItem = sb->FunctionTree->currentItem();
1641 
1642     if (currentItem == nullptr || currentItem->parent() == nullptr)
1643         return;
1644 
1645     for (auto &sc : KStarsFunctionList)
1646     {
1647         if (sc->prototype() == currentItem->text(0))
1648         {
1649             found = sc;
1650             break;
1651         }
1652     }
1653 
1654     for (auto &sc : SimClockFunctionList)
1655     {
1656         if (sc->prototype() == currentItem->text(0))
1657         {
1658             found = sc;
1659             break;
1660         }
1661     }
1662 
1663     if (found == nullptr)
1664     {
1665         sb->AddButton->setEnabled(false);
1666         qWarning() << i18n("Function index out of bounds.");
1667         return;
1668     }
1669 
1670     sb->AddButton->setEnabled(true);
1671     sb->FuncDoc->setHtml(found->description());
1672 }
1673 
1674 //Slots for Arg Widgets
slotFindCity()1675 void ScriptBuilder::slotFindCity()
1676 {
1677     QPointer<LocationDialog> ld = new LocationDialog(this);
1678 
1679     if (ld->exec() == QDialog::Accepted)
1680     {
1681         if (ld->selectedCity())
1682         {
1683             // set new location names
1684             argSetGeoLocation->CityName->setText(ld->selectedCityName());
1685             if (!ld->selectedProvinceName().isEmpty())
1686             {
1687                 argSetGeoLocation->ProvinceName->setText(ld->selectedProvinceName());
1688             }
1689             else
1690             {
1691                 argSetGeoLocation->ProvinceName->clear();
1692             }
1693             argSetGeoLocation->CountryName->setText(ld->selectedCountryName());
1694 
1695             ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
1696             if (sf->name() == "setGeoLocation")
1697             {
1698                 setUnsavedChanges(true);
1699 
1700                 sf->setArg(0, ld->selectedCityName());
1701                 sf->setArg(1, ld->selectedProvinceName());
1702                 sf->setArg(2, ld->selectedCountryName());
1703             }
1704             else
1705             {
1706                 warningMismatch("setGeoLocation");
1707             }
1708         }
1709     }
1710     delete ld;
1711 }
1712 
slotFindObject()1713 void ScriptBuilder::slotFindObject()
1714 {
1715     if (FindDialog::Instance()->exec() == QDialog::Accepted && FindDialog::Instance()->targetObject())
1716     {
1717         setUnsavedChanges(true);
1718 
1719         if (sender() == argLookToward->FindButton)
1720             argLookToward->FocusEdit->setEditText(FindDialog::Instance()->targetObject()->name());
1721         else
1722             argFindObject->NameEdit->setText(FindDialog::Instance()->targetObject()->name());
1723     }
1724 }
1725 
slotShowOptions()1726 void ScriptBuilder::slotShowOptions()
1727 {
1728     //Show tree-view of view options
1729     if (otv->exec() == QDialog::Accepted)
1730     {
1731         argChangeViewOption->OptionName->setCurrentIndex(
1732             argChangeViewOption->OptionName->findText(otv->optionsList()->currentItem()->text(0)));
1733     }
1734 }
1735 
slotLookToward()1736 void ScriptBuilder::slotLookToward()
1737 {
1738     ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
1739 
1740     if (sf->name() == "lookTowards")
1741     {
1742         setUnsavedChanges(true);
1743 
1744         sf->setArg(0, argLookToward->FocusEdit->currentText());
1745         sf->setValid(true);
1746     }
1747     else
1748     {
1749         warningMismatch("lookTowards");
1750     }
1751 }
1752 
slotArgFindObject()1753 void ScriptBuilder::slotArgFindObject()
1754 {
1755     ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
1756 
1757     if (sf->name() == "addLabel" || sf->name() == "removeLabel" || sf->name() == "addTrail" ||
1758             sf->name() == "removeTrail")
1759     {
1760         setUnsavedChanges(true);
1761 
1762         sf->setArg(0, argFindObject->NameEdit->text());
1763         sf->setValid(true);
1764     }
1765     else
1766     {
1767         warningMismatch(sf->name());
1768     }
1769 }
1770 
slotRa()1771 void ScriptBuilder::slotRa()
1772 {
1773     ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
1774 
1775     if (sf->name() == "setRaDec")
1776     {
1777         //do nothing if box is blank (because we could be clearing boxes while switching argWidgets)
1778         if (argSetRaDec->RABox->text().isEmpty())
1779             return;
1780 
1781         bool ok(false);
1782         dms ra = argSetRaDec->RABox->createDms(false, &ok);
1783         if (ok)
1784         {
1785             setUnsavedChanges(true);
1786 
1787             sf->setArg(0, QString("%1").arg(ra.Hours()));
1788             if (!sf->argVal(1).isEmpty())
1789                 sf->setValid(true);
1790         }
1791         else
1792         {
1793             sf->setArg(0, QString());
1794             sf->setValid(false);
1795         }
1796     }
1797     else
1798     {
1799         warningMismatch("setRaDec");
1800     }
1801 }
1802 
slotDec()1803 void ScriptBuilder::slotDec()
1804 {
1805     ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
1806 
1807     if (sf->name() == "setRaDec")
1808     {
1809         //do nothing if box is blank (because we could be clearing boxes while switching argWidgets)
1810         if (argSetRaDec->DecBox->text().isEmpty())
1811             return;
1812 
1813         bool ok(false);
1814         dms dec = argSetRaDec->DecBox->createDms(true, &ok);
1815         if (ok)
1816         {
1817             setUnsavedChanges(true);
1818 
1819             sf->setArg(1, QString("%1").arg(dec.Degrees()));
1820             if (!sf->argVal(0).isEmpty())
1821                 sf->setValid(true);
1822         }
1823         else
1824         {
1825             sf->setArg(1, QString());
1826             sf->setValid(false);
1827         }
1828     }
1829     else
1830     {
1831         warningMismatch("setRaDec");
1832     }
1833 }
1834 
slotAz()1835 void ScriptBuilder::slotAz()
1836 {
1837     ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
1838 
1839     if (sf->name() == "setAltAz")
1840     {
1841         //do nothing if box is blank (because we could be clearing boxes while switching argWidgets)
1842         if (argSetAltAz->AzBox->text().isEmpty())
1843             return;
1844 
1845         bool ok(false);
1846         dms az = argSetAltAz->AzBox->createDms(true, &ok);
1847         if (ok)
1848         {
1849             setUnsavedChanges(true);
1850             sf->setArg(1, QString("%1").arg(az.Degrees()));
1851             if (!sf->argVal(0).isEmpty())
1852                 sf->setValid(true);
1853         }
1854         else
1855         {
1856             sf->setArg(1, QString());
1857             sf->setValid(false);
1858         }
1859     }
1860     else
1861     {
1862         warningMismatch("setAltAz");
1863     }
1864 }
1865 
slotAlt()1866 void ScriptBuilder::slotAlt()
1867 {
1868     ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
1869 
1870     if (sf->name() == "setAltAz")
1871     {
1872         //do nothing if box is blank (because we could be clearing boxes while switching argWidgets)
1873         if (argSetAltAz->AltBox->text().isEmpty())
1874             return;
1875 
1876         bool ok(false);
1877         dms alt = argSetAltAz->AltBox->createDms(true, &ok);
1878         if (ok)
1879         {
1880             setUnsavedChanges(true);
1881 
1882             sf->setArg(0, QString("%1").arg(alt.Degrees()));
1883             if (!sf->argVal(1).isEmpty())
1884                 sf->setValid(true);
1885         }
1886         else
1887         {
1888             sf->setArg(0, QString());
1889             sf->setValid(false);
1890         }
1891     }
1892     else
1893     {
1894         warningMismatch("setAltAz");
1895     }
1896 }
1897 
slotChangeDate()1898 void ScriptBuilder::slotChangeDate()
1899 {
1900     ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
1901 
1902     if (sf->name() == "setLocalTime")
1903     {
1904         setUnsavedChanges(true);
1905 
1906         QDate date = argSetLocalTime->DateWidget->date();
1907 
1908         sf->setArg(0, QString("%1").arg(date.year()));
1909         sf->setArg(1, QString("%1").arg(date.month()));
1910         sf->setArg(2, QString("%1").arg(date.day()));
1911         if (!sf->argVal(3).isEmpty())
1912             sf->setValid(true);
1913     }
1914     else
1915     {
1916         warningMismatch("setLocalTime");
1917     }
1918 }
1919 
slotChangeTime()1920 void ScriptBuilder::slotChangeTime()
1921 {
1922     ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
1923 
1924     if (sf->name() == "setLocalTime")
1925     {
1926         setUnsavedChanges(true);
1927 
1928         QTime time = argSetLocalTime->TimeBox->time();
1929 
1930         sf->setArg(3, QString("%1").arg(time.hour()));
1931         sf->setArg(4, QString("%1").arg(time.minute()));
1932         sf->setArg(5, QString("%1").arg(time.second()));
1933         if (!sf->argVal(0).isEmpty())
1934             sf->setValid(true);
1935     }
1936     else
1937     {
1938         warningMismatch("setLocalTime");
1939     }
1940 }
1941 
slotWaitFor()1942 void ScriptBuilder::slotWaitFor()
1943 {
1944     ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
1945 
1946     if (sf->name() == "waitFor")
1947     {
1948         bool ok(false);
1949         int delay = argWaitFor->DelayBox->text().toInt(&ok);
1950 
1951         if (ok)
1952         {
1953             setUnsavedChanges(true);
1954 
1955             sf->setArg(0, QString("%1").arg(delay));
1956             sf->setValid(true);
1957         }
1958         else
1959         {
1960             sf->setValid(false);
1961         }
1962     }
1963     else
1964     {
1965         warningMismatch("waitFor");
1966     }
1967 }
1968 
slotWaitForKey()1969 void ScriptBuilder::slotWaitForKey()
1970 {
1971     ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
1972 
1973     if (sf->name() == "waitForKey")
1974     {
1975         QString sKey = argWaitForKey->WaitKeyEdit->text().trimmed();
1976 
1977         //DCOP script can only use single keystrokes; make sure entry is either one character,
1978         //or the word 'space'
1979         if (sKey.length() == 1 || sKey == "space")
1980         {
1981             setUnsavedChanges(true);
1982 
1983             sf->setArg(0, sKey);
1984             sf->setValid(true);
1985         }
1986         else
1987         {
1988             sf->setValid(false);
1989         }
1990     }
1991     else
1992     {
1993         warningMismatch("waitForKey");
1994     }
1995 }
1996 
slotTracking()1997 void ScriptBuilder::slotTracking()
1998 {
1999     ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
2000 
2001     if (sf->name() == "setTracking")
2002     {
2003         setUnsavedChanges(true);
2004 
2005         sf->setArg(0, (argSetTracking->CheckTrack->isChecked() ? i18n("true") : i18n("false")));
2006         sf->setValid(true);
2007     }
2008     else
2009     {
2010         warningMismatch("setTracking");
2011     }
2012 }
2013 
slotViewOption()2014 void ScriptBuilder::slotViewOption()
2015 {
2016     ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
2017 
2018     if (sf->name() == "changeViewOption")
2019     {
2020         if (argChangeViewOption->OptionName->currentIndex() >= 0 && argChangeViewOption->OptionValue->text().length())
2021         {
2022             setUnsavedChanges(true);
2023 
2024             sf->setArg(0, argChangeViewOption->OptionName->currentText());
2025             sf->setArg(1, argChangeViewOption->OptionValue->text());
2026             sf->setValid(true);
2027         }
2028         else
2029         {
2030             sf->setValid(false);
2031         }
2032     }
2033     else
2034     {
2035         warningMismatch("changeViewOption");
2036     }
2037 }
2038 
slotChangeCity()2039 void ScriptBuilder::slotChangeCity()
2040 {
2041     ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
2042 
2043     if (sf->name() == "setGeoLocation")
2044     {
2045         QString city = argSetGeoLocation->CityName->text();
2046 
2047         if (city.length())
2048         {
2049             setUnsavedChanges(true);
2050 
2051             sf->setArg(0, city);
2052             if (sf->argVal(2).length())
2053                 sf->setValid(true);
2054         }
2055         else
2056         {
2057             sf->setArg(0, QString());
2058             sf->setValid(false);
2059         }
2060     }
2061     else
2062     {
2063         warningMismatch("setGeoLocation");
2064     }
2065 }
2066 
slotChangeProvince()2067 void ScriptBuilder::slotChangeProvince()
2068 {
2069     ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
2070 
2071     if (sf->name() == "setGeoLocation")
2072     {
2073         QString province = argSetGeoLocation->ProvinceName->text();
2074 
2075         if (province.length())
2076         {
2077             setUnsavedChanges(true);
2078 
2079             sf->setArg(1, province);
2080             if (sf->argVal(0).length() && sf->argVal(2).length())
2081                 sf->setValid(true);
2082         }
2083         else
2084         {
2085             sf->setArg(1, QString());
2086             //might not be invalid
2087         }
2088     }
2089     else
2090     {
2091         warningMismatch("setGeoLocation");
2092     }
2093 }
2094 
slotChangeCountry()2095 void ScriptBuilder::slotChangeCountry()
2096 {
2097     ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
2098 
2099     if (sf->name() == "setGeoLocation")
2100     {
2101         QString country = argSetGeoLocation->CountryName->text();
2102 
2103         if (country.length())
2104         {
2105             setUnsavedChanges(true);
2106 
2107             sf->setArg(2, country);
2108             if (sf->argVal(0).length())
2109                 sf->setValid(true);
2110         }
2111         else
2112         {
2113             sf->setArg(2, QString());
2114             sf->setValid(false);
2115         }
2116     }
2117     else
2118     {
2119         warningMismatch("setGeoLocation");
2120     }
2121 }
2122 
slotTimeScale()2123 void ScriptBuilder::slotTimeScale()
2124 {
2125     ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
2126 
2127     if (sf->name() == "setClockScale")
2128     {
2129         setUnsavedChanges(true);
2130 
2131         sf->setArg(0, QString("%1").arg(argTimeScale->TimeScale->tsbox()->timeScale()));
2132         sf->setValid(true);
2133     }
2134     else
2135     {
2136         warningMismatch("setClockScale");
2137     }
2138 }
2139 
slotZoom()2140 void ScriptBuilder::slotZoom()
2141 {
2142     ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
2143 
2144     if (sf->name() == "zoom")
2145     {
2146         setUnsavedChanges(true);
2147 
2148         bool ok(false);
2149         argZoom->ZoomBox->text().toDouble(&ok);
2150         if (ok)
2151         {
2152             sf->setArg(0, argZoom->ZoomBox->text());
2153             sf->setValid(true);
2154         }
2155     }
2156     else
2157     {
2158         warningMismatch("zoom");
2159     }
2160 }
2161 
slotExportImage()2162 void ScriptBuilder::slotExportImage()
2163 {
2164     ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
2165 
2166     if (sf->name() == "exportImage")
2167     {
2168         setUnsavedChanges(true);
2169 
2170         sf->setArg(0, argExportImage->ExportFileName->url().url());
2171         sf->setArg(1, QString("%1").arg(argExportImage->ExportWidth->value()));
2172         sf->setArg(2, QString("%1").arg(argExportImage->ExportHeight->value()));
2173         sf->setValid(true);
2174     }
2175     else
2176     {
2177         warningMismatch("exportImage");
2178     }
2179 }
2180 
slotPrintImage()2181 void ScriptBuilder::slotPrintImage()
2182 {
2183     ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
2184 
2185     if (sf->name() == "printImage")
2186     {
2187         setUnsavedChanges(true);
2188 
2189         sf->setArg(0, (argPrintImage->UsePrintDialog->isChecked() ? i18n("true") : i18n("false")));
2190         sf->setArg(1, (argPrintImage->UseChartColors->isChecked() ? i18n("true") : i18n("false")));
2191         sf->setValid(true);
2192     }
2193     else
2194     {
2195         warningMismatch("exportImage");
2196     }
2197 }
2198 
slotChangeColorName()2199 void ScriptBuilder::slotChangeColorName()
2200 {
2201     ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
2202 
2203     if (sf->name() == "setColor")
2204     {
2205         setUnsavedChanges(true);
2206 
2207         argSetColor->ColorValue->setColor(KStarsData::Instance()->colorScheme()->colorAt(argSetColor->ColorName->currentIndex()));
2208         sf->setArg(0, KStarsData::Instance()->colorScheme()->keyAt(argSetColor->ColorName->currentIndex()));
2209         QString cname(argSetColor->ColorValue->color().name());
2210         //if ( cname.at(0) == '#' ) cname = "\\" + cname; //prepend a "\" so bash doesn't think we have a comment
2211         sf->setArg(1, cname);
2212         sf->setValid(true);
2213     }
2214     else
2215     {
2216         warningMismatch("setColor");
2217     }
2218 }
2219 
slotChangeColor()2220 void ScriptBuilder::slotChangeColor()
2221 {
2222     ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
2223 
2224     if (sf->name() == "setColor")
2225     {
2226         setUnsavedChanges(true);
2227 
2228         sf->setArg(0, KStarsData::Instance()->colorScheme()->keyAt(argSetColor->ColorName->currentIndex()));
2229         QString cname(argSetColor->ColorValue->color().name());
2230         //if ( cname.at(0) == '#' ) cname = "\\" + cname; //prepend a "\" so bash doesn't think we have a comment
2231         sf->setArg(1, cname);
2232         sf->setValid(true);
2233     }
2234     else
2235     {
2236         warningMismatch("setColor");
2237     }
2238 }
2239 
slotLoadColorScheme()2240 void ScriptBuilder::slotLoadColorScheme()
2241 {
2242     ScriptFunction *sf = ScriptList[sb->ScriptListBox->currentRow()];
2243 
2244     if (sf->name() == "loadColorScheme")
2245     {
2246         setUnsavedChanges(true);
2247 
2248         sf->setArg(0, '\"' + argLoadColorScheme->SchemeList->currentItem()->text() + '\"');
2249         sf->setValid(true);
2250     }
2251     else
2252     {
2253         warningMismatch("loadColorScheme");
2254     }
2255 }
2256 
slotClose()2257 void ScriptBuilder::slotClose()
2258 {
2259     saveWarning();
2260 
2261     if (!UnsavedChanges)
2262     {
2263         ScriptList.clear();
2264         sb->ScriptListBox->clear();
2265         sb->ArgStack->setCurrentWidget(argBlank);
2266         close();
2267     }
2268 }
2269 
2270 //TODO JM: INDI Scripting to be included in KDE 4.1
2271 
2272 #if 0
2273 void ScriptBuilder::slotINDIStartDeviceName()
2274 {
2275     ScriptFunction * sf = ScriptList[ sb->ScriptListBox->currentRow() ];
2276 
2277     if ( sf->name() == "startINDI" )
2278     {
2279         setUnsavedChanges( true );
2280 
2281         sf->setArg(0, argStartINDI->deviceName->text());
2282         sf->setArg(1, argStartINDI->LocalButton->isChecked() ? "true" : "false");
2283         sf->setValid(true);
2284     }
2285     else
2286     {
2287         warningMismatch( "startINDI" );
2288     }
2289 
2290 }
2291 
2292 void ScriptBuilder::slotINDIStartDeviceMode()
2293 {
2294 
2295     ScriptFunction * sf = ScriptList[ sb->ScriptListBox->currentRow() ];
2296 
2297     if ( sf->name() == "startINDI" )
2298     {
2299         setUnsavedChanges( true );
2300 
2301         sf->setArg(1, argStartINDI->LocalButton->isChecked() ? "true" : "false");
2302         sf->setValid(true);
2303     }
2304     else
2305     {
2306         warningMismatch( "startINDI" );
2307     }
2308 
2309 }
2310 
2311 void ScriptBuilder::slotINDISetDevice()
2312 {
2313 
2314     ScriptFunction * sf = ScriptList[ sb->ScriptListBox->currentRow() ];
2315 
2316     if ( sf->name() == "setINDIDevice" )
2317     {
2318         setUnsavedChanges( true );
2319 
2320         sf->setArg(0, argSetDeviceINDI->deviceName->text());
2321         sf->setValid(true);
2322     }
2323     else
2324     {
2325         warningMismatch( "startINDI" );
2326     }
2327 }
2328 
2329 void ScriptBuilder::slotINDIShutdown()
2330 {
2331 
2332     ScriptFunction * sf = ScriptList[ sb->ScriptListBox->currentRow() ];
2333 
2334     if ( sf->name() == "shutdownINDI" )
2335     {
2336         if (argShutdownINDI->deviceName->text().isEmpty())
2337         {
2338             sf->setValid(false);
2339             return;
2340         }
2341 
2342         if (sf->argVal(0) != argShutdownINDI->deviceName->text())
2343             setUnsavedChanges( true );
2344 
2345         sf->setArg(0, argShutdownINDI->deviceName->text());
2346         sf->setValid(true);
2347     }
2348     else
2349     {
2350         warningMismatch( "shutdownINDI" );
2351     }
2352 
2353 }
2354 
2355 void ScriptBuilder::slotINDISwitchDeviceConnection()
2356 {
2357 
2358     ScriptFunction * sf = ScriptList[ sb->ScriptListBox->currentRow() ];
2359 
2360     if ( sf->name() == "switchINDI" )
2361     {
2362 
2363         if (sf->argVal(0) != (argSwitchINDI->OnButton->isChecked() ? "true" : "false"))
2364             setUnsavedChanges( true );
2365 
2366         sf->setArg(0, argSwitchINDI->OnButton->isChecked() ? "true" : "false");
2367         sf->setValid(true);
2368     }
2369     else
2370     {
2371         warningMismatch( "switchINDI" );
2372     }
2373 
2374 }
2375 
2376 void ScriptBuilder::slotINDISetPortDevicePort()
2377 {
2378     ScriptFunction * sf = ScriptList[ sb->ScriptListBox->currentRow() ];
2379 
2380     if ( sf->name() == "setINDIPort" )
2381     {
2382 
2383         if (argSetPortINDI->devicePort->text().isEmpty())
2384         {
2385             sf->setValid(false);
2386             return;
2387         }
2388 
2389         if (sf->argVal(0) != argSetPortINDI->devicePort->text())
2390             setUnsavedChanges( true );
2391 
2392         sf->setArg(0, argSetPortINDI->devicePort->text());
2393         sf->setValid(true);
2394     }
2395     else
2396     {
2397         warningMismatch( "setINDIPort" );
2398     }
2399 
2400 }
2401 
2402 void ScriptBuilder::slotINDISetTargetCoordDeviceRA()
2403 {
2404     ScriptFunction * sf = ScriptList[ sb->ScriptListBox->currentRow() ];
2405 
2406     if ( sf->name() == "setINDITargetCoord" )
2407     {
2408         //do nothing if box is blank (because we could be clearing boxes while switching argWidgets)
2409         if ( argSetTargetCoordINDI->RABox->text().isEmpty() )
2410         {
2411             sf->setValid(false);
2412             return;
2413         }
2414 
2415         bool ok(false);
2416         dms ra = argSetTargetCoordINDI->RABox->createDms(false, &ok);
2417         if ( ok )
2418         {
2419 
2420             if (sf->argVal(0) != QString( "%1" ).arg( ra.Hours() ))
2421                 setUnsavedChanges( true );
2422 
2423             sf->setArg( 0, QString( "%1" ).arg( ra.Hours() ) );
2424             if ( ( ! sf->argVal(1).isEmpty() ))
2425                 sf->setValid( true );
2426             else
2427                 sf->setValid(false);
2428 
2429         }
2430         else
2431         {
2432             sf->setArg( 0, QString() );
2433             sf->setValid( false );
2434         }
2435     }
2436     else
2437     {
2438         warningMismatch( "setINDITargetCoord" );
2439     }
2440 
2441 }
2442 
2443 void ScriptBuilder::slotINDISetTargetCoordDeviceDEC()
2444 {
2445     ScriptFunction * sf = ScriptList[ sb->ScriptListBox->currentRow() ];
2446 
2447     if ( sf->name() == "setINDITargetCoord" )
2448     {
2449         //do nothing if box is blank (because we could be clearing boxes while switching argWidgets)
2450         if ( argSetTargetCoordINDI->DecBox->text().isEmpty() )
2451         {
2452             sf->setValid(false);
2453             return;
2454         }
2455 
2456         bool ok(false);
2457         dms dec = argSetTargetCoordINDI->DecBox->createDms(true, &ok);
2458         if ( ok )
2459         {
2460 
2461             if (sf->argVal(1) != QString( "%1" ).arg( dec.Degrees() ))
2462                 setUnsavedChanges( true );
2463 
2464             sf->setArg( 1, QString( "%1" ).arg( dec.Degrees() ) );
2465             if ( ( ! sf->argVal(0).isEmpty() ))
2466                 sf->setValid( true );
2467             else
2468                 sf->setValid(false);
2469 
2470         }
2471         else
2472         {
2473             sf->setArg( 1, QString() );
2474             sf->setValid( false );
2475         }
2476     }
2477     else
2478     {
2479         warningMismatch( "setINDITargetCoord" );
2480     }
2481 
2482 }
2483 
2484 void ScriptBuilder::slotINDISetTargetNameTargetName()
2485 {
2486 
2487     ScriptFunction * sf = ScriptList[ sb->ScriptListBox->currentRow() ];
2488 
2489     if ( sf->name() == "setINDITargetName" )
2490     {
2491         if (argSetTargetNameINDI->targetName->text().isEmpty())
2492         {
2493             sf->setValid(false);
2494             return;
2495         }
2496 
2497         if (sf->argVal(0) != argSetTargetNameINDI->targetName->text())
2498             setUnsavedChanges( true );
2499 
2500         sf->setArg(0, argSetTargetNameINDI->targetName->text());
2501         sf->setValid(true);
2502     }
2503     else
2504     {
2505         warningMismatch( "setINDITargetName" );
2506     }
2507 
2508 }
2509 
2510 void ScriptBuilder::slotINDISetActionName()
2511 {
2512     ScriptFunction * sf = ScriptList[ sb->ScriptListBox->currentRow() ];
2513 
2514     if ( sf->name() == "setINDIAction" )
2515     {
2516         if (argSetActionINDI->actionName->text().isEmpty())
2517         {
2518             sf->setValid(false);
2519             return;
2520         }
2521 
2522         if (sf->argVal(0) != argSetActionINDI->actionName->text())
2523             setUnsavedChanges( true );
2524 
2525         sf->setArg(0, argSetActionINDI->actionName->text());
2526         sf->setValid(true);
2527     }
2528     else
2529     {
2530         warningMismatch( "setINDIAction" );
2531     }
2532 
2533 }
2534 
2535 void ScriptBuilder::slotINDIWaitForActionName()
2536 {
2537     ScriptFunction * sf = ScriptList[ sb->ScriptListBox->currentRow() ];
2538 
2539     if ( sf->name() == "waitForINDIAction" )
2540     {
2541         if (argWaitForActionINDI->actionName->text().isEmpty())
2542         {
2543             sf->setValid(false);
2544             return;
2545         }
2546 
2547         if (sf->argVal(0) != argWaitForActionINDI->actionName->text())
2548             setUnsavedChanges( true );
2549 
2550         sf->setArg(0, argWaitForActionINDI->actionName->text());
2551         sf->setValid(true);
2552     }
2553     else
2554     {
2555         warningMismatch( "waitForINDIAction" );
2556     }
2557 
2558 }
2559 
2560 void ScriptBuilder::slotINDISetFocusSpeed()
2561 {
2562     ScriptFunction * sf = ScriptList[ sb->ScriptListBox->currentRow() ];
2563 
2564     if ( sf->name() == "setINDIFocusSpeed" )
2565     {
2566 
2567         if (sf->argVal(0).toInt() != argSetFocusSpeedINDI->speedIN->value())
2568             setUnsavedChanges( true );
2569 
2570         sf->setArg(0, QString("%1").arg(argSetFocusSpeedINDI->speedIN->value()));
2571         sf->setValid(true);
2572     }
2573     else
2574     {
2575         warningMismatch( "setINDIFocusSpeed" );
2576     }
2577 
2578 }
2579 
2580 void ScriptBuilder::slotINDIStartFocusDirection()
2581 {
2582     ScriptFunction * sf = ScriptList[ sb->ScriptListBox->currentRow() ];
2583 
2584     if ( sf->name() == "startINDIFocus" )
2585     {
2586         if (sf->argVal(0) != argStartFocusINDI->directionCombo->currentText())
2587             setUnsavedChanges( true );
2588 
2589         sf->setArg(0, argStartFocusINDI->directionCombo->currentText());
2590         sf->setValid(true);
2591     }
2592     else
2593     {
2594         warningMismatch( "startINDIFocus" );
2595     }
2596 
2597 }
2598 
2599 void ScriptBuilder::slotINDISetFocusTimeout()
2600 {
2601     ScriptFunction * sf = ScriptList[ sb->ScriptListBox->currentRow() ];
2602 
2603     if ( sf->name() == "setINDIFocusTimeout" )
2604     {
2605         if (sf->argVal(0).toInt() != argSetFocusTimeoutINDI->timeOut->value())
2606             setUnsavedChanges( true );
2607 
2608         sf->setArg(0, QString("%1").arg(argSetFocusTimeoutINDI->timeOut->value()));
2609         sf->setValid(true);
2610     }
2611     else
2612     {
2613         warningMismatch( "setINDIFocusTimeout" );
2614     }
2615 
2616 }
2617 
2618 void ScriptBuilder::slotINDISetGeoLocationDeviceLong()
2619 {
2620     ScriptFunction * sf = ScriptList[ sb->ScriptListBox->currentRow() ];
2621 
2622     if ( sf->name() == "setINDIGeoLocation" )
2623     {
2624         //do nothing if box is blank (because we could be clearing boxes while switching argWidgets)
2625         if ( argSetGeoLocationINDI->longBox->text().isEmpty())
2626         {
2627             sf->setValid(false);
2628             return;
2629         }
2630 
2631         bool ok(false);
2632         dms longitude = argSetGeoLocationINDI->longBox->createDms(true, &ok);
2633         if ( ok )
2634         {
2635 
2636             if (sf->argVal(0) != QString( "%1" ).arg( longitude.Degrees()))
2637                 setUnsavedChanges( true );
2638 
2639             sf->setArg( 0, QString( "%1" ).arg( longitude.Degrees() ) );
2640             if ( ! sf->argVal(1).isEmpty() )
2641                 sf->setValid( true );
2642             else
2643                 sf->setValid(false);
2644 
2645         }
2646         else
2647         {
2648             sf->setArg( 0, QString() );
2649             sf->setValid( false );
2650         }
2651     }
2652     else
2653     {
2654         warningMismatch( "setINDIGeoLocation" );
2655     }
2656 
2657 }
2658 
2659 void ScriptBuilder::slotINDISetGeoLocationDeviceLat()
2660 {
2661     ScriptFunction * sf = ScriptList[ sb->ScriptListBox->currentRow() ];
2662 
2663     if ( sf->name() == "setINDIGeoLocation" )
2664     {
2665         //do nothing if box is blank (because we could be clearing boxes while switching argWidgets)
2666         if ( argSetGeoLocationINDI->latBox->text().isEmpty() )
2667         {
2668             sf->setValid(false);
2669             return;
2670         }
2671 
2672         bool ok(false);
2673         dms latitude = argSetGeoLocationINDI->latBox->createDms(true, &ok);
2674         if ( ok )
2675         {
2676 
2677             if (sf->argVal(1) != QString( "%1" ).arg( latitude.Degrees()))
2678                 setUnsavedChanges( true );
2679 
2680             sf->setArg( 1, QString( "%1" ).arg( latitude.Degrees() ) );
2681             if ( ! sf->argVal(0).isEmpty() )
2682                 sf->setValid( true );
2683             else
2684                 sf->setValid(false);
2685 
2686         }
2687         else
2688         {
2689             sf->setArg( 1, QString() );
2690             sf->setValid( false );
2691         }
2692     }
2693     else
2694     {
2695         warningMismatch( "setINDIGeoLocation" );
2696     }
2697 
2698 }
2699 
2700 void ScriptBuilder::slotINDIStartExposureTimeout()
2701 {
2702     ScriptFunction * sf = ScriptList[ sb->ScriptListBox->currentRow() ];
2703 
2704     if ( sf->name() == "startINDIExposure" )
2705     {
2706 
2707         if (sf->argVal(0).toInt() != argStartExposureINDI->timeOut->value())
2708             setUnsavedChanges( true );
2709 
2710         sf->setArg(0, QString("%1").arg(argStartExposureINDI->timeOut->value()));
2711         sf->setValid(true);
2712     }
2713     else
2714     {
2715         warningMismatch( "startINDIExposure" );
2716     }
2717 
2718 }
2719 
2720 void ScriptBuilder::slotINDISetUTC()
2721 {
2722     ScriptFunction * sf = ScriptList[ sb->ScriptListBox->currentRow() ];
2723 
2724     if ( sf->name() == "setINDIUTC" )
2725     {
2726 
2727         if (argSetUTCINDI->UTC->text().isEmpty())
2728         {
2729             sf->setValid(false);
2730             return;
2731         }
2732 
2733         if (sf->argVal(0) != argSetUTCINDI->UTC->text())
2734             setUnsavedChanges( true );
2735 
2736         sf->setArg(0, argSetUTCINDI->UTC->text());
2737         sf->setValid(true);
2738     }
2739     else
2740     {
2741         warningMismatch( "setINDIUTC" );
2742     }
2743 
2744 }
2745 
2746 void ScriptBuilder::slotINDISetScopeAction()
2747 {
2748     ScriptFunction * sf = ScriptList[ sb->ScriptListBox->currentRow() ];
2749 
2750     if ( sf->name() == "setINDIScopeAction" )
2751     {
2752 
2753         if (sf->argVal(0) != argSetScopeActionINDI->actionCombo->currentText())
2754             setUnsavedChanges( true );
2755 
2756         sf->setArg(0, argSetScopeActionINDI->actionCombo->currentText());
2757         sf->setINDIProperty("CHECK");
2758         sf->setValid(true);
2759     }
2760     else
2761     {
2762         warningMismatch( "setINDIScopeAction" );
2763     }
2764 
2765 }
2766 
2767 void ScriptBuilder::slotINDISetFrameType()
2768 {
2769     ScriptFunction * sf = ScriptList[ sb->ScriptListBox->currentRow() ];
2770 
2771     if ( sf->name() == "setINDIFrameType" )
2772     {
2773 
2774         if (sf->argVal(0) != argSetFrameTypeINDI->typeCombo->currentText())
2775             setUnsavedChanges( true );
2776 
2777         sf->setArg(0, argSetFrameTypeINDI->typeCombo->currentText());
2778         sf->setValid(true);
2779     }
2780     else
2781     {
2782         warningMismatch( "setINDIFrameType" );
2783     }
2784 
2785 }
2786 
2787 void ScriptBuilder::slotINDISetCCDTemp()
2788 {
2789     ScriptFunction * sf = ScriptList[ sb->ScriptListBox->currentRow() ];
2790 
2791     if ( sf->name() == "setINDICCDTemp" )
2792     {
2793 
2794         if (sf->argVal(0).toInt() != argSetCCDTempINDI->temp->value())
2795             setUnsavedChanges( true );
2796 
2797         sf->setArg(0, QString("%1").arg(argSetCCDTempINDI->temp->value()));
2798         sf->setValid(true);
2799     }
2800     else
2801     {
2802         warningMismatch( "setINDICCDTemp" );
2803     }
2804 
2805 }
2806 
2807 void ScriptBuilder::slotINDISetFilterNum()
2808 {
2809 
2810     ScriptFunction * sf = ScriptList[ sb->ScriptListBox->currentRow() ];
2811 
2812     if ( sf->name() == "setINDIFilterNum" )
2813     {
2814 
2815         if (sf->argVal(0).toInt() != argSetFilterNumINDI->filter_num->value())
2816             setUnsavedChanges( true );
2817 
2818         sf->setArg(0, QString("%1").arg(argSetFilterNumINDI->filter_num->value()));
2819         sf->setValid(true);
2820     }
2821     else
2822     {
2823         warningMismatch( "setINDIFilterNum" );
2824     }
2825 
2826 
2827 }
2828 #endif
2829 
warningMismatch(const QString & expected) const2830 void ScriptBuilder::warningMismatch(const QString &expected) const
2831 {
2832     qWarning() << i18n("Mismatch between function and Arg widget (expected %1.)", QString(expected));
2833 }
2834