Kstars

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

KDE's Doxygen guidelines are available online.