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

KDE's Doxygen guidelines are available online.