1 /*
2  * Stellarium Telescope Control Plug-in
3  *
4  * Copyright (C) 2009-2011 Bogdan Marinov (this file)
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA  02110-1335, USA.
19 */
20 
21 #include "Dialog.hpp"
22 #include "StelApp.hpp"
23 #include "StelCore.hpp"
24 #include "StelModuleMgr.hpp"
25 #include "StelFileMgr.hpp"
26 #include "StelLocaleMgr.hpp"
27 #include "StelStyle.hpp"
28 #include "StelTranslator.hpp"
29 #include "TelescopeControl.hpp"
30 #include "TelescopeConfigurationDialog.hpp"
31 #include "TelescopeDialog.hpp"
32 #include "ui_telescopeDialog.h"
33 #include "StelGui.hpp"
34 #include <QDebug>
35 #include <QFrame>
36 #include <QTimer>
37 #include <QFile>
38 #include <QFileDialog>
39 #include <QHash>
40 #include <QHeaderView>
41 #include <QSettings>
42 #include <QStandardItem>
43 #include <QRegularExpression>
44 
45 using namespace TelescopeControlGlobals;
46 
47 
TelescopeDialog()48 TelescopeDialog::TelescopeDialog()
49 	: StelDialog("TelescopeControl")
50 	, telescopeCount(0)
51 	, configuredSlot(0)
52 	, configuredTelescopeIsNew(false)
53 {
54 	telescopeStatus[0] = StatusNA;
55 	telescopeType[0] = ConnectionNA;
56 
57 	ui = new Ui_telescopeDialogForm;
58 
59 	//TODO: Fix this - it's in the same plugin
60 	telescopeManager = GETSTELMODULE(TelescopeControl);
61 	telescopeListModel = new QStandardItemModel(0, ColumnCount);
62 
63 	//TODO: This shouldn't be a hash...
64 	statusString[StatusNA] = QString(N_("N/A"));
65 	statusString[StatusStarting] = QString(N_("Starting"));
66 	statusString[StatusConnecting] = QString(N_("Connecting"));
67 	statusString[StatusConnected] = QString(N_("Connected"));
68 	statusString[StatusDisconnected] = QString(N_("Disconnected"));
69 	statusString[StatusStopped] = QString(N_("Stopped"));
70 }
71 
~TelescopeDialog()72 TelescopeDialog::~TelescopeDialog()
73 {
74 	delete ui;
75 
76 	delete telescopeListModel;
77 }
78 
retranslate()79 void TelescopeDialog::retranslate()
80 {
81 	if (dialog)
82 	{
83 		ui->retranslateUi(dialog);
84 		setAboutText();
85 		setHeaderNames();
86 		updateWarningTexts();
87 
88 		//Retranslate type strings
89 		for (int i = 0; i < telescopeListModel->rowCount(); i++)
90 		{
91 			QStandardItem* item = telescopeListModel->item(i, ColumnType);
92 			QString original = item->data(Qt::UserRole).toString();
93 			QModelIndex index = telescopeListModel->index(i, ColumnType);
94 			telescopeListModel->setData(index, q_(original), Qt::DisplayRole);
95 		}
96 	}
97 }
98 
99 // Initialize the dialog widgets and connect the signals/slots
createDialogContent()100 void TelescopeDialog::createDialogContent()
101 {
102 	ui->setupUi(dialog);
103 
104 	// Kinetic scrolling
105 	kineticScrollingList << ui->telescopeTreeView << ui->textBrowserHelp << ui->textBrowserAbout;
106 	StelGui* gui= dynamic_cast<StelGui*>(StelApp::getInstance().getGui());
107 	if (gui)
108 	{
109 		enableKineticScrolling(gui->getFlagUseKineticScrolling());
110 		connect(gui, SIGNAL(flagUseKineticScrollingChanged(bool)), this, SLOT(enableKineticScrolling(bool)));
111 	}
112 
113 	//Inherited connect
114 	connect(&StelApp::getInstance(), SIGNAL(languageChanged()), this, SLOT(retranslate()));
115 	connect(ui->closeStelWindow, SIGNAL(clicked()), this, SLOT(close()));
116 	connect(ui->TitleBar, SIGNAL(movedTo(QPoint)), this, SLOT(handleMovedTo(QPoint)));
117 
118 	//Connect: sender, signal, receiver, method
119 	//Page: Telescopes
120 	connect(ui->pushButtonChangeStatus, SIGNAL(clicked()), this, SLOT(buttonChangeStatusPressed()));
121 	connect(ui->pushButtonConfigure, SIGNAL(clicked()), this, SLOT(buttonConfigurePressed()));
122 	connect(ui->pushButtonAdd, SIGNAL(clicked()), this, SLOT(buttonAddPressed()));
123 	connect(ui->pushButtonRemove, SIGNAL(clicked()), this, SLOT(buttonRemovePressed()));
124 
125 	connect(ui->telescopeTreeView, SIGNAL(clicked (const QModelIndex &)), this, SLOT(selectTelecope(const QModelIndex &)));
126 	//connect(ui->telescopeTreeView, SIGNAL(activated (const QModelIndex &)), this, SLOT(configureTelescope(const QModelIndex &)));
127 
128 	//Page: Options:
129 	connect(ui->checkBoxReticles, SIGNAL(clicked(bool)),
130 	        telescopeManager, SLOT(setFlagTelescopeReticles(bool)));
131 	connect(ui->checkBoxLabels, SIGNAL(clicked(bool)),
132 	        telescopeManager, SLOT(setFlagTelescopeLabels(bool)));
133 	connect(ui->checkBoxCircles, SIGNAL(clicked(bool)),
134 	        telescopeManager, SLOT(setFlagTelescopeCircles(bool)));
135 
136 	connect(ui->checkBoxEnableLogs, SIGNAL(toggled(bool)), telescopeManager, SLOT(setFlagUseTelescopeServerLogs(bool)));
137 
138 	connect(ui->checkBoxUseExecutables, SIGNAL(toggled(bool)), ui->labelExecutablesDirectory, SLOT(setEnabled(bool)));
139 	connect(ui->checkBoxUseExecutables, SIGNAL(toggled(bool)), ui->lineEditExecutablesDirectory, SLOT(setEnabled(bool)));
140 	connect(ui->checkBoxUseExecutables, SIGNAL(toggled(bool)), ui->pushButtonPickExecutablesDirectory, SLOT(setEnabled(bool)));
141 	connect(ui->checkBoxUseExecutables, SIGNAL(toggled(bool)), this, SLOT(checkBoxUseExecutablesToggled(bool)));
142 
143 	connect(ui->pushButtonPickExecutablesDirectory, SIGNAL(clicked()), this, SLOT(buttonBrowseServerDirectoryPressed()));
144 
145 	//In other dialogs:
146 	connect(&configurationDialog, SIGNAL(changesDiscarded()), this, SLOT(discardChanges()));
147 	connect(&configurationDialog, SIGNAL(changesSaved(QString, ConnectionType)), this, SLOT(saveChanges(QString, ConnectionType)));
148 
149 	//Initialize the style
150 	updateStyle();
151 
152 	//Initializing the list of telescopes
153 	telescopeListModel->setColumnCount(ColumnCount);
154 	setHeaderNames();
155 
156 	ui->telescopeTreeView->setModel(telescopeListModel);
157 	ui->telescopeTreeView->header()->setSectionsMovable(false);
158 	ui->telescopeTreeView->header()->setSectionResizeMode(ColumnSlot, QHeaderView::ResizeToContents);
159 	ui->telescopeTreeView->header()->setStretchLastSection(true);
160 
161 	//Populating the list
162 	//Cycle the slots
163 	for (int slotNumber = MIN_SLOT_NUMBER; slotNumber < SLOT_NUMBER_LIMIT; slotNumber++)
164 	{
165 		//Slot #
166 		//int slotNumber = (i+1)%SLOT_COUNT;//Making sure slot 0 is last
167 
168 		//Make sure that this is initialized for all slots
169 		telescopeStatus[slotNumber] = StatusNA;
170 
171 		//Read the telescope properties
172 		QString name;
173 		ConnectionType connectionType;
174 		QString equinox;
175 		QString host;
176 		int portTCP;
177 		int delay;
178 		bool connectAtStartup;
179 		QList<double> circles;
180 		QString serverName;
181 		QString portSerial;
182 		QString rts2Url;
183 		QString rts2Username;
184 		QString rts2Password;
185 		int rts2Refresh;
186 		QString ascomDeviceId;
187 		bool ascomUseDeviceEqCoordType;
188 
189 		if(!telescopeManager->getTelescopeAtSlot(slotNumber, connectionType, name, equinox, host, portTCP, delay, connectAtStartup, circles, serverName, portSerial, rts2Url, rts2Username, rts2Password, rts2Refresh, ascomDeviceId, ascomUseDeviceEqCoordType))
190 			continue;
191 
192 		//Determine the server type
193 		telescopeType[slotNumber] = connectionType;
194 
195 		//Determine the telescope's status
196 		if (telescopeManager->isConnectedClientAtSlot(slotNumber))
197 		{
198 			telescopeStatus[slotNumber] = StatusConnected;
199 		}
200 		else
201 		{
202 			//TODO: Fix this!
203 			//At startup everything exists and attempts to connect
204 			telescopeStatus[slotNumber] = StatusConnecting;
205 		}
206 
207 		addModelRow(slotNumber, connectionType, telescopeStatus[slotNumber], name);
208 
209 		//After everything is done, count this as loaded
210 		telescopeCount++;
211 	}
212 
213 	//Finished populating the table, let's sort it by slot number
214 	//ui->telescopeTreeView->setSortingEnabled(true);//Set in the .ui file
215 	ui->telescopeTreeView->sortByColumn(ColumnSlot, Qt::AscendingOrder);
216 	//(Works even when the table is empty)
217 	//(Makes redundant the delay of 0 above)
218 
219 	//TODO: Reuse code.
220 	if(telescopeCount > 0)
221 	{
222 		ui->telescopeTreeView->setFocus();
223 		ui->telescopeTreeView->header()->setSectionResizeMode(ColumnType, QHeaderView::ResizeToContents);
224 	}
225 	else
226 	{
227 		ui->pushButtonChangeStatus->setEnabled(false);
228 		ui->pushButtonConfigure->setEnabled(false);
229 		ui->pushButtonRemove->setEnabled(false);
230 		ui->pushButtonAdd->setFocus();
231 	}
232 	updateWarningTexts();
233 
234 	if(telescopeCount >= SLOT_COUNT)
235 		ui->pushButtonAdd->setEnabled(false);
236 
237 	//Checkboxes
238 	ui->checkBoxReticles->setChecked(telescopeManager->getFlagTelescopeReticles());
239 	ui->checkBoxLabels->setChecked(telescopeManager->getFlagTelescopeLabels());
240 	ui->checkBoxCircles->setChecked(telescopeManager->getFlagTelescopeCircles());
241 	ui->checkBoxEnableLogs->setChecked(telescopeManager->getFlagUseTelescopeServerLogs());
242 
243 	//Telescope server directory
244 	ui->checkBoxUseExecutables->setChecked(telescopeManager->getFlagUseServerExecutables());
245 	ui->lineEditExecutablesDirectory->setText(telescopeManager->getServerExecutablesDirectoryPath());
246 
247 	//About page
248 	setAboutText();
249 
250 	//Everything must be initialized by now, start the updateTimer
251 	//TODO: Find if it's possible to run it only when the dialog is visible
252 	QTimer* updateTimer = new QTimer(this);
253 	connect(updateTimer, SIGNAL(timeout()), this, SLOT(updateTelescopeStates()));
254 	updateTimer->start(200);
255 }
256 
setAboutText()257 void TelescopeDialog::setAboutText()
258 {
259 	// Regexp to replace {text} with an HTML link.
260 	QRegularExpression a_rx("[{]([^{]*)[}]");
261 
262 	//TODO: Expand
263 	QString aboutPage = "<html><head></head><body>";
264 	aboutPage += "<h2>" + q_("Telescope Control plug-in") + "</h2><table width=\"90%\">";
265 	aboutPage += "<tr width=\"30%\"><td><strong>" + q_("Version") + ":</strong></td><td>" + TELESCOPE_CONTROL_PLUGIN_VERSION + "</td></tr>";
266 	aboutPage += "<tr><td><strong>" + q_("License") + ":</strong></td><td>" + TELESCOPE_CONTROL_PLUGIN_LICENSE + "</td></tr>";
267 	aboutPage += "<tr><td rowspan=5><strong>" + q_("Authors") + "</strong></td><td>Johannes Gajdosik</td></td>";
268 	aboutPage += "<tr><td>Bogdan Marinov &lt;bogdan.marinov84@gmail.com&gt; (" + q_("Plug-in and GUI programming") + ")</td></tr>";
269 	aboutPage += "<tr><td>Gion Kunz &lt;gion.kunz@gmail.com&gt; (" + q_("ASCOM Telescope Client") + ")</td></tr>";
270 	aboutPage += "<tr><td>Petr Kubánek (" + q_("RTS2 support") + ")</td></tr>";
271 	aboutPage += "<tr><td>Alessandro Siniscalchi &lt;asiniscalchi@gmail.com&gt; (" + q_("INDI Telescope Client") + ")</td></tr>";
272 	aboutPage += "<tr><td rowspan=3><strong>" + q_("Contributors") + ":</strong></td><td>Alexander Wolf</td></tr>";
273 	aboutPage += "<tr><td>Michael Heinz</td></tr>";
274 	aboutPage += "<tr><td>Alexandros Kosiaris</td></tr>";
275 	aboutPage += "</table>";
276 
277 	aboutPage += "<p>" + q_("This plug-in is based on and reuses a lot of code under the GNU General Public License:") + "</p><ul>";
278 	aboutPage += "<li>" + q_("the Telescope, TelescopeDummy, TelescopeTcp and TelescopeMgr classes in Stellarium's code (the client side of Stellarium's original telescope control feature);") + "</li>";
279 	aboutPage += "<li>" + q_("the telescope server core code (licensed under the LGPL)") + "</li>";
280 	aboutPage += "<li>" + q_("the TelescopeServerLx200 telescope server core code (originally licensed under the LGPL)");
281 	aboutPage += "<br/>" + q_("Author of all of the above - the client, the server core, and the LX200 server, along with the Stellarium telescope control network protocol (over TCP/IP), is <b>Johannes Gajdosik</b>.") + "</li>";
282 	aboutPage += "<li>" + q_("the TelescopeServerNexStar telescope server core code (originally licensed under the LGPL, based on TelescopeServerLx200) by <b>Michael Heinz</b>.") + "</li>";
283 	aboutPage += "<li>" + q_("INDI by <b>Alessandro Siniscalchi</b>.") + "</li></ul>";
284 
285 	aboutPage += StelApp::getInstance().getModuleMgr().getStandardSupportLinksInfo("Telescope Control plugin");
286 	aboutPage += "</body></html>";
287 
288 	QString helpPage = "<html><head></head><body>";
289 	// TRANSLATORS: The text between braces is the text of an HTML link.
290 	helpPage += "<p>" + q_("A more complete and up-to-date documentation for this plug-in can be found on the {Telescope Control} page in the Stellarium Wiki.").replace(a_rx, "<a href=\"http://stellarium.sourceforge.net/wiki/index.php/Telescope_Control_plug-in\">\\1</a>") + "</p>";
291 	helpPage += "<h3><a name=\"top\" />" + q_("Contents") + "</h3><ul>";
292 	helpPage += "<li><a href=\"#Abilities_and_limitations\">" + q_("Abilities and limitations") + "</a></li>";
293 	helpPage += "<li><a href=\"#originalfeature\">" + q_("The original telescope control feature") + "</a></li>";
294 	helpPage += "<li><a href=\"#usingthisplugin\">" + q_("Using this plug-in") + "</a></li>";
295 	helpPage += "<li><a href=\"#mainwindow\">" + q_("Main window ('Telescopes')") + "</a></li>";
296 	helpPage += "<li><a href=\"#configwindow\">" + q_("Telescope configuration window") + "</a><ul>";
297 	helpPage += "<li><a href=\"#connection_type\">" + q_("Connection type") + "</a></li>";
298 	helpPage += "<li><a href=\"#telescope_properties\">" + q_("Telescope properties") + "</a></li>";
299 	helpPage += "<li><a href=\"#device_settings\">" + q_("Device settings") + "</a></li>";
300 	helpPage += "<li><a href=\"#connection_settings\">" + q_("Connection settings") + "</a></li>";
301 	helpPage += "<li><a href=\"#fovcircles\">" + q_("Field of view indicators") + "</a></li></ul></li>";
302 	helpPage += "<li><a href=\"#slew_to\">" + q_("'Slew telescope to' window") + "</a></li>";
303 	helpPage += "<li><a href=\"#commands\">" + q_("Telescope commands") + "</a></li>";
304 	helpPage += "<li><a href=\"#devices\">" + q_("Supported devices") + "</a></li>";
305 	helpPage += "<li><a href=\"#virtual_telescope\">" + q_("Virtual telescope") + "</a></li></ul>";
306 
307 	helpPage += "<h3><a name=\"Abilities_and_limitations\" />" + q_("Abilities and limitations") + "</h3>";
308 	helpPage += "<p>" + q_("This plug-in allows Stellarium to send only '<b>slew</b>' ('go to') commands to the device and to receive its current position. It cannot issue any other commands, so users should be aware of the possibility for mount collisions and similar situations. (To abort a slew, you can start another one to a safe position.)") + "</p>";
309 	helpPage += "<p>" + q_("As of the current version, this plug-in doesn't allow satellite tracking, and is not very suitable for lunar or planetary observations.") + "</p>";
310 	helpPage += "<p><span style=\"color: red; font-weight: bolder;\">" + q_("WARNING: Stellarium CANNOT prevent your telescope from being pointed at the Sun.") + "</span></p><ul>";
311 	helpPage += "<li>" + q_("Never point your telescope at the Sun without a proper solar filter installed. The powerful light amplified by the telescope WILL cause irreversible damage to your eyes and/or your equipment.") + "</li>";
312 	helpPage += "<li>" + q_("Even if you don't do it deliberately, a slew during daylight hours may cause your telescope to point at the sun on its way to the given destination, so it is strongly recommended to avoid using the telescope control feature before sunset without appropriate protection.") + "</li></ul>";
313 	helpPage += "<p><a href=\"#top\"><small>[" + q_("Back to top") + "]</small></a></p>";
314 
315 	helpPage += "<h3><a name=\"originalfeature\" />" + q_("The original telescope control feature") + "</h3>";
316 	helpPage += "<p>" + q_("As of Stellarium 0.10.5, the original telescope control feature has been removed. There is no longer a way to control a telescope with Stellarium without this plug-in.") + "</p>";
317 	helpPage += "<p><a href=\"#top\"><small>[" + q_("Back to top") + "]</small></a></p>";
318 
319 	helpPage += "<h3><a name=\"usingthisplugin\" />" + q_("Using this plug-in") + "</h3>";
320 	helpPage += "<p>" + q_("Here are two general ways to control a device with this plug-in, depending on the situation:") + "</p><ul>";
321 	helpPage += "<li><b>" + q_("DIRECT CONNECTION") + "</b>: ";
322 
323 	// TRANSLATORS: The text between braces is the text of an HTML link.
324 	helpPage += q_("A {device supported by the plug-in} is connected with a cable to the computer running Stellarium;").replace(a_rx, "<a href=\"#devices\">\\1</a>");
325 	helpPage += "</li>";
326 	helpPage += "<li><b>" + q_("INDIRECT CONNECTION") + "</b>: <ul>";
327 	helpPage += "<li>";
328 	// TRANSLATORS: The text between braces is the text of an HTML link.
329 	helpPage += q_("A device is connected to the same computer but it is driven by a {stand-alone telescope server program}").replace(a_rx, "<a href=\"http://stellarium.sourceforge.net/wiki/index.php/Telescope_Control_%28client-server%29\">\\1</a>") + " ";
330 	// TRANSLATORS: The text between braces is the text of an HTML link.
331 	helpPage += q_("or a {third-party application} <b>that can 'talk' to Stellarium</b>;").replace(a_rx, "<a href=\"http://stellarium.sourceforge.net/wiki/index.php/Telescope_Control#Third_party_applications\">\\1</a>");
332 	helpPage += "</li>";
333 	helpPage += "<li>" + q_("A device is connected to a remote computer and the software that drives it can 'talk' to Stellarium <i>over the network</i>; this software can be either one of Stellarium's stand-alone telescope servers, or a third party application.") + "</li></ul></li></ul>";
334 	helpPage += "<p>";
335 	// TRANSLATORS: The text between braces is the text of an HTML link.
336 	helpPage += "<p>" + q_("Most older telescopes use cables that connect to a {serial port} (RS-232), the newer ones use USB (Universal Serial Bus).").replace(a_rx, "<a href=\"http://meta.wikimedia.org/wiki/wikipedia:en:serial_port\">\\1</a>")
337 		 + " " + q_("On Linux and Mac OS X both cases are handled identically by the plug-in. On Windows, a USB connection may require a 'virtual serial port' software, if it is not supplied with the cable or the telescope.")
338 		 + " " + q_("Such a software creates a virtual ('fake') COM port that corresponds to the real USB port so it can be used by the plug-in.")
339 		 + " " + q_("On all three platforms, if the computer has no 'classic' serial ports and the telescope can connect only to a serial port, a serial-to-USB (RS-232-to-USB) adapter may be necessary.") + "</p>";
340 	helpPage += "<p>" + q_("Telescope set-up (setting geographical coordinates, performing alignment, etc.) should be done before connecting the telescope to Stellarium.") + "</p>";
341 	helpPage += "<p><a href=\"#top\"><small>[" + q_("Back to top") + "]</small></a></p>";
342 
343 	helpPage += "<h3><a name=\"mainwindow\" />" + q_("Main window ('Telescopes')") + "</h3>";
344 	helpPage += "<p>" + q_("The plug-in's main window can be opened:") + "</p><ul>";
345 	helpPage += "<li>" + q_("By pressing the 'configure' button for the plug-in in the 'Plugins' tab of Stellarium's Configuration window (opened by pressing <b>F2</b> or the respective button in the left toolbar).") + "</li>";
346 	helpPage += "<li>";
347 	// TRANSLATORS: The text between braces is the text of an HTML link.
348 	helpPage += q_("By pressing the 'Configure telescopes...' button in the {'Slew to' window} (opened by pressing <b>Ctrl+0</b> or the respective button on the bottom toolbar).").replace(a_rx, "<a href=\"#slew_to\">\\1</a>");
349 	helpPage += "</li></ul>";
350 	helpPage += "<p>" + q_("The <b>Telescopes</b> tab displays a list of the telescope connections that have been set up:") + "</p><ul>";
351 	helpPage += "<li>" + q_("The number (<b>#</b>) column shows the number used to control this telescope. For example, for telescope #2, the shortcut is Ctrl+2.") + "</li>";
352 	helpPage += "<li>" + q_("The <b>Status</b> column indicates if this connection is currently active or not. Unfortunately, there are some cases in which 'Connected' is displayed when no working connection exists.") + "</li>";
353 	helpPage += "<li>" + q_("The <b>Type</b> field indicates what kind of connection is this:") + "</li><ul>";
354 	helpPage += "<li>";
355 	// TRANSLATORS: The text between braces is the text of an HTML link.
356 	helpPage += q_("<b>virtual</b> means a {virtual telescope};").replace(a_rx, "<a href=\"#virtual_telescope\">\\1</a>");
357 	helpPage += "</li>";
358 	helpPage += "<li>";
359 	// TRANSLATORS: The text between braces is the text of an HTML link.
360 	helpPage += q_("<b>local, Stellarium</b> means a DIRECT connection to the telescope (see {above});").replace(a_rx, "<a href=\"#usingthisplugin\">\\1</a>");
361 	helpPage += "</li>";
362 	helpPage += "<li>" + q_("<b>local, external</b> means an INDIRECT connection to a program running on the same computer;") + "</li>";
363 	helpPage += "<li>" + q_("<b>remote, unknown</b> means an INDIRECT connection over a network to a remote machine.") + "</li></ul></li></ul>";
364 	helpPage += "<p>" + q_("To set up a new telescope connection, press the <b>Add</b> button. To modify the configuration of an existing connection, select it in the list and press the <b>Configure</b> button. In both cases, a telescope connection configuration window will open.") + "</p>";
365 	helpPage += "<p><a href=\"#top\"><small>[" + q_("Back to top") + "]</small></a></p>";
366 
367 	helpPage += "<h3><a name=\"configwindow\" />" + q_("Telescope configuration window") + "</h3>";
368 
369 	helpPage += "<h4><a name=\"connection_type\" />" + q_("Connection type") + "</h4>";
370 	helpPage += "<p>";
371 	// TRANSLATORS: The text between braces is the text of an HTML link.
372 	helpPage += q_("The topmost field represents the choice between the two types of connections (see {above}):").replace(a_rx, "<a href=\"#usingthisplugin\">\\1</a>");
373 	helpPage += "</p>";
374 	helpPage += "<p><b>" + q_("Telescope controlled by:") + "</b></p><ul>";
375 	helpPage += "<li>" + q_("<b>Stellarium, directly through a serial port</b> is the DIRECT case") + "</li>";
376 	helpPage += "<li>" + q_("<b>External software or a remote computer</b> is the INDIRECT case") + "</li>";
377 	helpPage += "<li>";
378 	// TRANSLATORS: The text between braces is the text of an HTML link.
379 	helpPage += q_("<b>Nothing, just simulate one (a moving reticle)</b> is a {virtual telescope} (no connection)").replace(a_rx, "<a href=\"#virtual_telescope\">\\1</a>");
380 	helpPage += "</li></ul>";
381 	helpPage += "<p><a href=\"#top\"><small>[" + q_("Back to top") + "]</small></a></p>";
382 
383 	helpPage += "<h4><a name=\"telescope_properties\" />" + q_("Telescope properties") + "</h4>";
384 	helpPage += "<p>" + q_("<b>Name</b> is the label that will be displayed on the screen next to the telescope reticle.") + "</p>";
385 	helpPage += "<p>" + q_("<b>Connection delay</b>: If the movement of the telescope reticle on the screen is uneven, you can try increasing or decreasing this value.") + "</p>";
386 	helpPage += "<p>" + q_("<b>Coordinate system</b>: Some Celestron telescopes have had their firmware updated and now interpret the coordinates they receive as coordinates that use the equinox of the date (EOD, also known as JNow), making necessary this override.") + "</p>";
387 	helpPage += "<p>" + q_("<b>Start/connect at startup</b>: Check this option if you want Stellarium to attempt to connect to the telescope immediately after it starts.")
388 		 + " " + q_("Otherwise, to start the telescope, you need to open the main window, select that telescope and press the 'Start/Connect' button.") + "</p>";
389 	helpPage += "<p><a href=\"#top\"><small>[" + q_("Back to top") + "]</small></a></p>";
390 
391 	helpPage += "<h4><a name=\"device_settings\" />" + q_("Device settings") + "</h4>";
392 	helpPage += "<p>";
393 	// TRANSLATORS: The text between braces is the text of an HTML link.
394 	helpPage += q_("This section is active only for DIRECT connections (see {above}).").replace(a_rx, "<a href=\"#usingthisplugin\">\\1</a>");
395 	helpPage += "</p>";
396 	helpPage += "<p>" + q_("<b>Serial port</b> sets the serial port used by the telescope.") + "</p>";
397 	helpPage += "<p>" + q_("There is a pop-up box that suggests some default values:") + "</p><ul>";
398 	helpPage += "<li>" + q_("On Windows, serial ports COM1 to COM10;") + "</li>";
399 	helpPage += "<li>" + q_("On Linux, serial ports /dev/ttyS0 to /dev/ttyS3 and USB ports /dev/ttyUSB0 to /dev/ttyUSB3;") + "</li>";
400 	helpPage += "<li>" + q_("On Mac OS X, the list is empty as it names its ports in a peculiar way.") + "</li></ul>";
401 	helpPage += "<p>" + q_("If you are using an USB cable, the default serial port of your telescope most probably is not in the list of suggestions.") + "</p>";
402 	helpPage += "<p>" + q_("To list all valid serial port names in Mac OS X, open a terminal and type:") + "<br /><samp>ls /dev/*</samp></p>";
403 	helpPage += "<p>" + q_("This will list all devices, the full name of your serial port should be somewhere in the list (for example, '/dev/cu.usbserial-FTDFZVMK').") + "</p>";
404 	helpPage += "<p>";
405 	// TRANSLATORS: The text between braces is the text of an HTML link.
406 	helpPage += q_("<b>Device model</b>: see {Supported devices} below.").replace(a_rx, "<a href=\"#devices\">\\1</a>");
407 	helpPage += "</p>";
408 	helpPage += "<p><a href=\"#top\"><small>[" + q_("Back to top") + "]</small></a></p>";
409 
410 	helpPage += "<h4><a name=\"connection_settings\" />" + q_("Connection settings") + "</h4>";
411 	helpPage += "<p>";
412 	// TRANSLATORS: The text between braces is the text of an HTML link.
413 	helpPage += q_("Both fields here refer to communication over a network ({TCP/IP}).").replace(a_rx, "<a href=\"http://meta.wikimedia.org/wiki/wikipedia:en:TCP/IP\">\\1</a>") + " ";
414 	// TRANSLATORS: The text between braces is the text of an HTML link.
415 	helpPage += q_("Doing something with them is necessary only for INDIRECT connections (see {above}).").replace(a_rx, "<a href=\"#usingthisplugin\">\\1</a>") + " ";
416 	helpPage += "</p>";
417 	helpPage += "<p>";
418 	// TRANSLATORS: The text between braces is the text of an HTML link.
419 	helpPage += q_("<b>Host</b> can be either a host name or an {IPv4} address such as '127.0.0.1'. The default value of 'localhost' means 'this computer'.").replace(a_rx, "<a href=\"http://meta.wikimedia.org/wiki/wikipedia:en:IPv4\">\\1</a>");
420 	helpPage += "</p>";
421 	helpPage += "<p>" + q_("<b>Port</b> refers to the TCP port used for communication. The default value depends on the telescope number and ranges between 10001 and 10009.") + "</p>";
422 	helpPage += "<p>" + q_("Both values are ignored for DIRECT connections.") + "</p>";
423 	helpPage += "<p>" + q_("For INDIRECT connections, modifying the default host name value makes sense only if you are attempting a remote connection over a network.")
424 		 + " " + q_("In this case, it should be the name or IP address of the computer that runs a program that runs the telescope.") + "</p>";
425 	helpPage += "<p><a href=\"#top\"><small>[" + q_("Back to top") + "]</small></a></p>";
426 
427 	helpPage += "<h4><a name=\"fovcircles\" />" + q_("Field of view indicators") + "</h4>";
428 	helpPage += "<p>" + q_("A series of circles representing different fields of view can be added around the telescope marker. This is a relic from the times before the <strong>Oculars</strong> plug-in existed.") + "</p>";
429 	helpPage += "<p>" + q_("In the telescope configuration window, click on 'User Interface Settings'.")
430 		 + " " + q_("Mark the 'Use field of view indicators' option, then enter a list of values separated with commas in the field below.")
431 		 + " " + q_("The values are interpreted as degrees of arc.") + "</p>";
432 	helpPage += "<p>";
433 	// TRANSLATORS: The text between braces is the text of an HTML link.
434 	helpPage += q_("This can be used in combination with a {virtual telescope} to display a moving reticle with the Telrad circles.").replace(a_rx, "<a href=\"#virtual_telescope\">\\1</a>");
435 	helpPage += "</p>";
436 	helpPage += "<p><a href=\"#top\"><small>[" + q_("Back to top") + "]</small></a></p>";
437 
438 	helpPage += "<h3><a name=\"slew_to\" />" + q_("'Slew telescope to' window") + "</h3>";
439 	helpPage += "<p>" + q_("The 'Slew telescope to' window can be opened by pressing <b>Ctrl+0</b> or the respective button in the bottom toolbar.") + "</p>";
440 	helpPage += "<p>" + q_("It contains two fields for entering celestial coordinates, selectors for the preferred format (Hours-Minutes-Seconds, Degrees-Minutes-Seconds, or Decimal degrees), a drop-down list and two buttons.") + "</p>";
441 	helpPage += "<p>" + q_("The drop-down list contains the names of the currently connected devices.") + " ";
442 	helpPage += q_("If no devices are connected, it will remain empty, and the 'Slew' button will be disabled.") + "</p>";
443 	helpPage += "<p>" + q_("Pressing the <b>Slew</b> button slews the selected device to the selected set of coordinates.") + " ";
444 	// TRANSLATORS: The text between braces is the text of an HTML link.
445 	helpPage += q_("See the section about {keyboard commands} below for other ways of controlling the device.").replace(a_rx, "<a href=\"#commands\">\\1</a>");
446 	helpPage += "</p>";
447 	helpPage += "<p>";
448 	// TRANSLATORS: The text between braces is the text of an HTML link.
449 	helpPage += q_("Pressing the <b>Configure telescopes...</b> button opens the {main window} of the plug-in.").replace(a_rx, "<a href=\"#mainwindow\">\\1</a>");
450 	helpPage += "</p>";
451 	helpPage += "<p>" + q_("<b>TIP:</b> Inside the 'Slew' window, underlined letters indicate that pressing 'Alt + underlined letter' can be used instead of clicking.") + " ";
452 	helpPage +=  q_("For example, pressing <b>Alt+S</b> is equivalent to clicking the 'Slew' button, pressing <b>Alt+E</b> switches to decimal degree format, etc.") + "</p>";
453 	helpPage += "<p><a href=\"#top\"><small>[" + q_("Back to top") + "]</small></a></p>";
454 
455 	helpPage += "<h3><a name=\"commands\" />" + q_("Sending commands") + "</h3>";
456 	helpPage += "<p>" + q_("Once a telescope is successfully started/connected, Stellarium displays a telescope reticle labelled with the telescope's name on its current position in the sky.")
457 		 + " " + q_("The reticle is an object like every other in Stellarium - it can be selected with the mouse, it can be tracked and it appears as an object in the 'Search' window.") + "</p>";
458 	helpPage += "<p>" + q_("<b>To point a device to an object:</b> Select an object (e.g. a star) and press the number of the device while holding down the <b>Ctrl</b> key.")
459 		 + " (" + q_("For example, Ctrl+1 for telescope #1.") + ") "
460 		 + q_("This will move the telescope to the selected object.") + "</p>";
461 	helpPage += "<p>" + q_("<b>To point a device to the center of the view:</b> Press the number of the device while holding down the <b>Alt</b> key.")
462 		 + " (" + q_("For example, Alt+1 for telescope #1.") + ") "
463 		 + q_("This will slew the device to the point in the center of the current view.")
464 		 + " (" + q_("If you move the view after issuing the command, the target won't change unless you issue another command.") + ")</p>";
465 	helpPage += "<p>";
466 	// TRANSLATORS: The text between braces is the text of an HTML link.
467 	helpPage += q_("<b>To point a device to a given set of coordinates:</b> Use the {'Slew to' window} (press <b>Ctrl+0</b>).").replace(a_rx, "<a href=\"#slew_to\">\\1</a>");
468 	helpPage += "</p>";
469 	helpPage += "<p><a href=\"#top\"><small>[" + q_("Back to top") + "]</small></a></p>";
470 
471 	helpPage += "<h3><a name=\"devices\" />" + q_("Supported devices") + "</h3>";
472 	helpPage += "<p>";
473 	// TRANSLATORS: The text between braces is the text of an HTML link.
474 	helpPage += q_("All devices listed in the {'Device model' list} are convenience definitions using one of the two built-in interfaces: the Meade LX200 (the Meade Autostar controller) interface and the Celestron NexStar interface.").replace(a_rx, "<a href=\"#device_settings\">\\1</a>");
475 	helpPage += "</p>";
476 	helpPage += "<p>" + q_("The device list contains the following:") + "</p><dl>";
477 	helpPage += "<dt><b>Celestron NexStar (compatible)</b></dt><dd>" + q_("Any device using the NexStar interface.") + "</dd>";
478 	helpPage += "<dt><b>Losmandy G-11</b></dt><dd>" + q_("A computerized telescope mount made by Losmandy (Meade LX-200/Autostar interface).") + "</dd>";
479 	helpPage += "<dt><b>Meade Autostar compatible</b></dt><dd>" + q_("Any device using the LX-200/Autostar interface.") + "</dd>";
480 	helpPage += "<dt><b>Meade ETX-70 (#494 Autostar, #506 CCS)</b></dt><dd>" + q_("The Meade ETX-70 telescope with the #494 Autostar controller and the #506 Connector Cable Set.") + " ";
481 	// TRANSLATORS: The text between braces is the text of an HTML link.
482 	helpPage += q_("According to the tester, it is a bit slow, so its default setting of %1'Connection delay'%2 is 1.5 seconds instead of 0.5 seconds.").replace(a_rx, "<a href=\"#telescope_properties\">\\1</a>");
483 	helpPage += "</dd>";
484 	helpPage += "<dt><b>Meade LX200 (compatible)</b></dt><dd>" + q_("Any device using the LX-200/Autostar interface.") + "</dd>";
485 	helpPage += "<dt><b>Sky-Watcher SynScan AZ mount</b></dt><dd>" + q_("The Sky-Watcher SynScan AZ GoTo mount is used in a number of telescopes.") + "</dd>";
486 	helpPage += "<dt><b>Sky-Watcher SynScan (version 3 or later)</b></dt><dd>" + q_("<b>SynScan</b> is also the name of the hand controller used in other Sky-Watcher GoTo mounts, and it seems that any mount that uses a SynScan controller version 3.0 or greater is supported by the plug-in, as it uses the NexStar protocol.") + "</dd>";
487 	helpPage += "<dt><b>Wildcard Innovations Argo Navis (Meade mode)</b></dt><dd>" + q_("Argo Navis is a 'Digital Telescope Computer' by Wildcard Innovations.")
488 		 + " " + q_("It is an advanced digital setting circle that turns an ordinary telescope (for example, a dobsonian) into a 'Push To' telescope (a telescope that uses a computer to find targets and human power to move the telescope itself).")
489 		 + " " + q_("Just don't forget to set it to Meade compatibility mode and set the baud rate to 9600B")
490 		 + "<sup><a href=\"http://www.iceinspace.com.au/forum/showpost.php?p=554948&amp;postcount=18\">1</a></sup>.</dd></dl>";
491 	helpPage += "<p><a href=\"#top\"><small>[" + q_("Back to top") + "]</small></a></p>";
492 
493 	helpPage += "<h3><a name=\"virtual_telescope\" />" + q_("Virtual telescope") + "</h3>";
494 	helpPage += "<p>" + q_("If you want to test this plug-in without an actual device connected to the computer, choose <b>Nothing, just simulate one (a moving reticle)</b> in the <b>Telescope controlled by:</b> field. It will show a telescope reticle that will react in the same way as the reticle of a real telescope controlled by the plug-in.") + "</p>";
495 	helpPage += "<p>";
496 	// TRANSLATORS: The text between braces is the text of an HTML link.
497 	helpPage += q_("See the section above about {field of view indicators} for a possible practical application (emulating 'Telrad' circles).").replace(a_rx, "<a href=\"#fovcircles\">\\1</a>");
498 	helpPage += "</p>";
499 	helpPage += "<p>";
500 	// TRANSLATORS: The text between braces is the text of an HTML link.
501 	helpPage += q_("This feature is equivalent to the 'Dummy' type of telescope supported by {Stellarium's original telescope control feature}.").replace(a_rx, "<a href=\"http://stellarium.sourceforge.net/wiki/index.php/Telescope_Control_%28client-server%29\">\\1</a>");
502 	helpPage += "</p>";
503 	helpPage += "<p><a href=\"#top\"><small>[" + q_("Back to top") + "]</small></a></p>";
504 
505 	helpPage += "</body></html>";
506 
507 	StelGui* gui = dynamic_cast<StelGui*>(StelApp::getInstance().getGui());
508 	if (gui)
509 	{
510 		ui->textBrowserAbout->document()->setDefaultStyleSheet(QString(gui->getStelStyle().htmlStyleSheet));
511 		ui->textBrowserHelp->document()->setDefaultStyleSheet(QString(gui->getStelStyle().htmlStyleSheet));
512 	}
513 	ui->textBrowserAbout->setHtml(aboutPage);
514 	ui->textBrowserHelp->setHtml(helpPage);
515 }
516 
setHeaderNames()517 void TelescopeDialog::setHeaderNames()
518 {
519 	QStringList headerStrings;
520 	// TRANSLATORS: Symbol for "number"
521 	headerStrings << q_("#");
522 	//headerStrings << "Start";
523 	headerStrings << q_("Status");
524 	headerStrings << q_("Type");
525 	headerStrings << q_("Name");
526 	telescopeListModel->setHorizontalHeaderLabels(headerStrings);
527 }
528 
updateWarningTexts()529 void TelescopeDialog::updateWarningTexts()
530 {
531 	QString text;
532 	if (telescopeCount > 0)
533 	{
534 #ifdef Q_OS_MAC
535 		QString modifierName = "Command";
536 #else
537 		QString modifierName = "Ctrl";
538 #endif
539 
540 		text = QString(q_("To slew a connected telescope to an object (for example, a star), select that object, then hold down the %1 key and press the key with that telescope's number. To slew it to the center of the current view, hold down the Alt key and press the key with that telescope's number.")).arg(modifierName);
541 	}
542 	else
543 	{
544 		if (telescopeManager->getDeviceModels().isEmpty())
545 		{
546 			// TRANSLATORS: Currently, it is very unlikely if not impossible to actually see this text. :)
547 			text = q_("No device model descriptions are available. Stellarium will not be able to control a telescope on its own, but it is still possible to do it through an external application or to connect to a remote host.");
548 		}
549 		else
550 		{
551 			// TRANSLATORS: The translated name of the Add button is automatically inserted.
552 			text = QString(q_("Press the \"%1\" button to set up a new telescope connection.")).arg(ui->pushButtonAdd->text());
553 		}
554 	}
555 
556 	ui->labelWarning->setText(text);
557 }
558 
getTypeLabel(ConnectionType type)559 QString TelescopeDialog::getTypeLabel(ConnectionType type)
560 {
561 	QString typeLabel;
562 	switch (type)
563 	{
564 		case ConnectionInternal:
565 			// TRANSLATORS: Telescope connection type
566 			typeLabel = N_("local, Stellarium");
567 			break;
568 		case ConnectionLocal:
569 			// TRANSLATORS: Telescope connection type
570 			typeLabel = N_("local, external");
571 			break;
572 		case ConnectionRemote:
573 			// TRANSLATORS: Telescope connection type
574 			typeLabel = N_("remote, unknown");
575 			break;
576 		case ConnectionVirtual:
577 			// TRANSLATORS: Telescope connection type
578 			typeLabel = N_("virtual");
579 			break;
580 		case ConnectionRTS2:
581 			// TRANSLATORS: Telescope connection type
582 			typeLabel = N_("remote, RTS2");
583 			break;
584 		case ConnectionINDI:
585 			// TRANSLATORS: Telescope connection type
586 			typeLabel = N_("remote, INDI/INDIGO");
587 			break;
588 		case ConnectionASCOM:
589 			// TRANSLATORS: Telescope connection type
590 			typeLabel = N_("local, ASCOM");
591 			break;
592 		default:
593 			;
594 	}
595 	return typeLabel;
596 }
597 
addModelRow(int number,ConnectionType type,TelescopeStatus status,const QString & name)598 void TelescopeDialog::addModelRow(int number,
599                                   ConnectionType type,
600                                   TelescopeStatus status,
601                                   const QString& name)
602 {
603 	Q_ASSERT(telescopeListModel);
604 
605 	QStandardItem* tempItem = Q_NULLPTR;
606 	int lastRow = telescopeListModel->rowCount();
607 	// Number
608 	tempItem = new QStandardItem(QString::number(number));
609 	tempItem->setEditable(false);
610 	telescopeListModel->setItem(lastRow, ColumnSlot, tempItem);
611 
612 	// Checkbox
613 	//TODO: This is not updated, because it was commented out
614 	//tempItem = new QStandardItem;
615 	//tempItem->setEditable(false);
616 	//tempItem->setCheckable(true);
617 	//tempItem->setCheckState(Qt::Checked);
618 	//tempItem->setData("If checked, this telescope will start when Stellarium is started", Qt::ToolTipRole);
619 	//telescopeListModel->setItem(lastRow, ColumnStartup, tempItem);//Start-up checkbox
620 
621 	//Status
622 	tempItem = new QStandardItem(q_(statusString[status]));
623 	tempItem->setEditable(false);
624 	telescopeListModel->setItem(lastRow, ColumnStatus, tempItem);
625 
626 	//Type
627 	QString typeLabel = getTypeLabel(type);
628 	tempItem = new QStandardItem(q_(typeLabel));
629 	tempItem->setEditable(false);
630 	tempItem->setData(typeLabel, Qt::UserRole);
631 	telescopeListModel->setItem(lastRow, ColumnType, tempItem);
632 
633 	//Name
634 	tempItem = new QStandardItem(name);
635 	tempItem->setEditable(false);
636 	telescopeListModel->setItem(lastRow, ColumnName, tempItem);
637 }
638 
updateModelRow(int rowNumber,ConnectionType type,TelescopeStatus status,const QString & name)639 void TelescopeDialog::updateModelRow(int rowNumber,
640                                      ConnectionType type,
641                                      TelescopeStatus status,
642                                      const QString& name)
643 {
644 	Q_ASSERT(telescopeListModel);
645 	if (rowNumber > telescopeListModel->rowCount())
646 		return;
647 
648 	//The slot number doesn't need to be updated. :)
649 	//Status
650 	QString statusLabel = q_(statusString[status]);
651 	QModelIndex index = telescopeListModel->index(rowNumber, ColumnStatus);
652 	telescopeListModel->setData(index, statusLabel, Qt::DisplayRole);
653 
654 	//Type
655 	QString typeLabel = getTypeLabel(type);
656 	index = telescopeListModel->index(rowNumber, ColumnType);
657 	telescopeListModel->setData(index, typeLabel, Qt::UserRole);
658 	telescopeListModel->setData(index, q_(typeLabel), Qt::DisplayRole);
659 
660 	//Name
661 	index = telescopeListModel->index(rowNumber, ColumnName);
662 	telescopeListModel->setData(index, name, Qt::DisplayRole);
663 }
664 
665 
selectTelecope(const QModelIndex & index)666 void TelescopeDialog::selectTelecope(const QModelIndex & index)
667 {
668 	//Extract selected item index
669 	int selectedSlot = telescopeListModel->data( telescopeListModel->index(index.row(),0) ).toInt();
670 	updateStatusButtonForSlot(selectedSlot);
671 
672 	//In all cases
673 	ui->pushButtonRemove->setEnabled(true);
674 }
675 
configureTelescope(const QModelIndex & currentIndex)676 void TelescopeDialog::configureTelescope(const QModelIndex & currentIndex)
677 {
678 	configuredTelescopeIsNew = false;
679 	configuredSlot = telescopeListModel->data( telescopeListModel->index(currentIndex.row(), ColumnSlot) ).toInt();
680 
681 	//Stop the telescope first if necessary
682 	if(telescopeType[configuredSlot] != ConnectionInternal && telescopeStatus[configuredSlot] != StatusDisconnected)
683 	{
684 		if(telescopeManager->stopTelescopeAtSlot(configuredSlot)) //Act as "Disconnect"
685 				telescopeStatus[configuredSlot] = StatusDisconnected;
686 		else
687 			return;
688 	}
689 	else if(telescopeStatus[configuredSlot] != StatusStopped)
690 	{
691 		if(telescopeManager->stopTelescopeAtSlot(configuredSlot)) //Act as "Stop"
692 					telescopeStatus[configuredSlot] = StatusStopped;
693 	}
694 	//Update the status in the list
695 	int curRow = ui->telescopeTreeView->currentIndex().row();
696 	QModelIndex curIndex = telescopeListModel->index(curRow, ColumnStatus);
697 	QString string = q_(statusString[telescopeStatus[configuredSlot]]);
698 	telescopeListModel->setData(curIndex, string, Qt::DisplayRole);
699 
700 	setVisible(false);
701 	configurationDialog.setVisible(true); //This should be called first to actually create the dialog content
702 
703 	configurationDialog.initExistingTelescopeConfiguration(configuredSlot);
704 }
705 
buttonChangeStatusPressed()706 void TelescopeDialog::buttonChangeStatusPressed()
707 {
708 	if(!ui->telescopeTreeView->currentIndex().isValid())
709 		return;
710 
711 	//Extract selected slot
712 	int selectedSlot = telescopeListModel->data( telescopeListModel->index(ui->telescopeTreeView->currentIndex().row(), ColumnSlot) ).toInt();
713 
714 	//TODO: As most of these are asynchronous actions, it looks like that there should be a queue...
715 
716 	if(telescopeType[selectedSlot] != ConnectionInternal)
717 	{
718 		//Can't be launched by Stellarium -> can't be stopped by Stellarium
719 		//Can be only connected/disconnected
720 		if(telescopeStatus[selectedSlot] == StatusDisconnected)
721 		{
722 			if(telescopeManager->startTelescopeAtSlot(selectedSlot)) //Act as "Connect"
723 				telescopeStatus[selectedSlot] = StatusConnecting;
724 		}
725 		else
726 		{
727 			if(telescopeManager->stopTelescopeAtSlot(selectedSlot)) //Act as "Disconnect"
728 				telescopeStatus[selectedSlot] = StatusDisconnected;
729 		}
730 	}
731 	else
732 	{
733 		switch(telescopeStatus[selectedSlot]) //Why the switch?
734 		{
735 			case StatusNA:
736 			case StatusStopped:
737 			{
738 				if(telescopeManager->startTelescopeAtSlot(selectedSlot)) //Act as "Start"
739 					telescopeStatus[selectedSlot] = StatusConnecting;
740 			}
741 			break;
742 			case StatusConnecting:
743 			case StatusConnected:
744 			{
745 				if(telescopeManager->stopTelescopeAtSlot(selectedSlot)) //Act as "Stop"
746 					telescopeStatus[selectedSlot] = StatusStopped;
747 			}
748 			break;
749 			default:
750 				break;
751 		}
752 	}
753 
754 	//Update the status in the list
755 	int curRow = ui->telescopeTreeView->currentIndex().row();
756 	QModelIndex curIndex = telescopeListModel->index(curRow, ColumnStatus);
757 	QString string = q_(statusString[telescopeStatus[selectedSlot]]);
758 	telescopeListModel->setData(curIndex, string, Qt::DisplayRole);
759 }
760 
buttonConfigurePressed()761 void TelescopeDialog::buttonConfigurePressed()
762 {
763 	if(ui->telescopeTreeView->currentIndex().isValid())
764 		configureTelescope(ui->telescopeTreeView->currentIndex());
765 }
766 
buttonAddPressed()767 void TelescopeDialog::buttonAddPressed()
768 {
769 	if(telescopeCount >= SLOT_COUNT)
770 		return;
771 
772 	configuredTelescopeIsNew = true;
773 
774 	//Find the first unoccupied slot (there is at least one)
775 	for (configuredSlot = MIN_SLOT_NUMBER; configuredSlot < SLOT_NUMBER_LIMIT; configuredSlot++)
776 	{
777 		//configuredSlot = (i+1)%SLOT_COUNT;
778 		if(telescopeStatus[configuredSlot] == StatusNA)
779 			break;
780 	}
781 
782 	setVisible(false);
783 	configurationDialog.setVisible(true); //This should be called first to actually create the dialog content
784 	configurationDialog.initNewTelescopeConfiguration(configuredSlot);
785 }
786 
buttonRemovePressed()787 void TelescopeDialog::buttonRemovePressed()
788 {
789 	if(!ui->telescopeTreeView->currentIndex().isValid())
790 		return;
791 
792 	//Extract selected slot
793 	int selectedSlot = telescopeListModel->data( telescopeListModel->index(ui->telescopeTreeView->currentIndex().row(),0) ).toInt();
794 
795 	//Stop the telescope if necessary and remove it
796 	if(telescopeManager->stopTelescopeAtSlot(selectedSlot))
797 	{
798 		//TODO: Update status?
799 		if(!telescopeManager->removeTelescopeAtSlot(selectedSlot))
800 		{
801 			//TODO: Add debug
802 			return;
803 		}
804 	}
805 	else
806 	{
807 		//TODO: Add debug
808 		return;
809 	}
810 
811 	//Save the changes to file
812 	telescopeManager->saveTelescopes();
813 
814 	telescopeStatus[selectedSlot] = StatusNA;
815 	telescopeCount -= 1;
816 
817 //Update the interface to reflect the changes:
818 
819 	//Make sure that the header section keeps it size
820 	if(telescopeCount == 0)
821 		ui->telescopeTreeView->header()->setSectionResizeMode(ColumnType, QHeaderView::Interactive);
822 
823 	//Remove the telescope from the table/tree
824 	telescopeListModel->removeRow(ui->telescopeTreeView->currentIndex().row());
825 
826 	//If there are less than the maximal number of telescopes now, new ones can be added
827 	if(telescopeCount < SLOT_COUNT)
828 		ui->pushButtonAdd->setEnabled(true);
829 
830 	//If there are no telescopes left, disable some buttons
831 	if(telescopeCount == 0)
832 	{
833 		//TODO: Fix the phantom text of the Status button (reuse code?)
834 		//IDEA: Vsible/invisible instead of enabled/disabled?
835 		//The other buttons expand to take the place (delete spacers)
836 		ui->pushButtonChangeStatus->setEnabled(false);
837 		ui->pushButtonConfigure->setEnabled(false);
838 		ui->pushButtonRemove->setEnabled(false);
839 	}
840 	else
841 	{
842 		ui->telescopeTreeView->setCurrentIndex(telescopeListModel->index(0,0));
843 	}
844 	updateWarningTexts();
845 }
846 
saveChanges(QString name,ConnectionType type)847 void TelescopeDialog::saveChanges(QString name, ConnectionType type)
848 {
849 	//Save the changes to file
850 	telescopeManager->saveTelescopes();
851 
852 	//Type and server properties
853 	telescopeType[configuredSlot] = type;
854 	switch (type)
855 	{
856 		case ConnectionVirtual:
857 			telescopeStatus[configuredSlot] = StatusStopped;
858 			break;
859 
860 		case ConnectionInternal:
861 			if(configuredTelescopeIsNew)
862 				telescopeStatus[configuredSlot] = StatusStopped;//TODO: Is there a point? Isn't it better to force the status update method?
863 			break;
864 
865 		case ConnectionLocal:
866 			telescopeStatus[configuredSlot] = StatusDisconnected;
867 			break;
868 
869 		case ConnectionRemote:
870 		default:
871 			telescopeStatus[configuredSlot] = StatusDisconnected;
872 	}
873 
874 	//Update the model/list
875 	TelescopeStatus status = telescopeStatus[configuredSlot];
876 	if(configuredTelescopeIsNew)
877 	{
878 		addModelRow(configuredSlot, type, status, name);
879 		telescopeCount++;
880 	}
881 	else
882 	{
883 		int currentRow = ui->telescopeTreeView->currentIndex().row();
884 		updateModelRow(currentRow, type, status, name);
885 	}
886 	//Sort the updated table by slot number
887 	ui->telescopeTreeView->sortByColumn(ColumnSlot, Qt::AscendingOrder);
888 
889 	//Can't add more telescopes if they have reached the maximum number
890 	if (telescopeCount >= SLOT_COUNT)
891 		ui->pushButtonAdd->setEnabled(false);
892 
893 	//
894 	if (telescopeCount == 0)
895 	{
896 		ui->pushButtonChangeStatus->setEnabled(false);
897 		ui->pushButtonConfigure->setEnabled(false);
898 		ui->pushButtonRemove->setEnabled(false);
899 		ui->telescopeTreeView->header()->setSectionResizeMode(ColumnType, QHeaderView::Interactive);
900 	}
901 	else
902 	{
903 		ui->telescopeTreeView->setFocus();
904 		ui->telescopeTreeView->setCurrentIndex(telescopeListModel->index(0,0));
905 		ui->pushButtonConfigure->setEnabled(true);
906 		ui->pushButtonRemove->setEnabled(true);
907 		ui->telescopeTreeView->header()->setSectionResizeMode(ColumnType, QHeaderView::ResizeToContents);
908 	}
909 	updateWarningTexts();
910 
911 	configuredTelescopeIsNew = false;
912 	configurationDialog.setVisible(false);
913 	setVisible(true);//Brings the current window to the foreground
914 }
915 
discardChanges()916 void TelescopeDialog::discardChanges()
917 {
918 	configurationDialog.setVisible(false);
919 	setVisible(true);//Brings the current window to the foreground
920 
921 	if (telescopeCount >= SLOT_COUNT)
922 		ui->pushButtonAdd->setEnabled(false);
923 	if (telescopeCount == 0)
924 		ui->pushButtonRemove->setEnabled(false);
925 
926 	configuredTelescopeIsNew = false;
927 }
928 
updateTelescopeStates()929 void TelescopeDialog::updateTelescopeStates()
930 {
931 	if(telescopeCount == 0)
932 		return;
933 
934 	int slotNumber = -1;
935 	for (int i=0; i<(telescopeListModel->rowCount()); i++)
936 	{
937 		slotNumber = telescopeListModel->data( telescopeListModel->index(i, ColumnSlot) ).toInt();
938 		//TODO: Check if these cover all possibilites
939 		if (telescopeManager->isConnectedClientAtSlot(slotNumber))
940 		{
941 			telescopeStatus[slotNumber] = StatusConnected;
942 		}
943 		else if(telescopeManager->isExistingClientAtSlot(slotNumber))
944 		{
945 			telescopeStatus[slotNumber] = StatusConnecting;
946 		}
947 		else
948 		{
949 			if(telescopeType[slotNumber] == ConnectionInternal)
950 				telescopeStatus[slotNumber] = StatusStopped;
951 			else
952 				telescopeStatus[slotNumber] = StatusDisconnected;
953 		}
954 
955 		//Update the status in the list
956 		QModelIndex index = telescopeListModel->index(i, ColumnStatus);
957 		QString statusStr = q_(statusString[telescopeStatus[slotNumber]]);
958 		telescopeListModel->setData(index, statusStr, Qt::DisplayRole);
959 	}
960 
961 	if(ui->telescopeTreeView->currentIndex().isValid())
962 	{
963 		int selectedSlot = telescopeListModel->data( telescopeListModel->index(ui->telescopeTreeView->currentIndex().row(), ColumnSlot) ).toInt();
964 		//Update the ChangeStatus button
965 		updateStatusButtonForSlot(selectedSlot);
966 	}
967 }
968 
updateStatusButtonForSlot(int selectedSlot)969 void TelescopeDialog::updateStatusButtonForSlot(int selectedSlot)
970 {
971 	if(telescopeType[selectedSlot] != ConnectionInternal)
972 	{
973 		//Can't be launched by Stellarium => can't be stopped by Stellarium
974 		//Can be only connected/disconnected
975 		if(telescopeStatus[selectedSlot] == StatusDisconnected)
976 		{
977 			setStatusButtonToConnect();
978 			ui->pushButtonChangeStatus->setEnabled(true);
979 		}
980 		else
981 		{
982 			setStatusButtonToDisconnect();
983 			ui->pushButtonChangeStatus->setEnabled(true);
984 		}
985 	}
986 	else
987 	{
988 		switch(telescopeStatus[selectedSlot])
989 		{
990 			case StatusNA:
991 			case StatusStopped:
992 				setStatusButtonToStart();
993 				ui->pushButtonChangeStatus->setEnabled(true);
994 				break;
995 			case StatusConnected:
996 			case StatusConnecting:
997 				setStatusButtonToStop();
998 				ui->pushButtonChangeStatus->setEnabled(true);
999 				break;
1000 			default:
1001 				setStatusButtonToStart();
1002 				ui->pushButtonChangeStatus->setEnabled(false);
1003 				ui->pushButtonConfigure->setEnabled(false);
1004 				ui->pushButtonRemove->setEnabled(false);
1005 				break;
1006 		}
1007 	}
1008 }
1009 
setStatusButtonToStart()1010 void TelescopeDialog::setStatusButtonToStart()
1011 {
1012 	ui->pushButtonChangeStatus->setText(q_("Start"));
1013 	ui->pushButtonChangeStatus->setIcon(QIcon(":/graphicGui/uibtStart.png"));
1014         ui->pushButtonChangeStatus->setToolTip(q_("Start the selected local telescope"));
1015 }
1016 
setStatusButtonToStop()1017 void TelescopeDialog::setStatusButtonToStop()
1018 {
1019 	ui->pushButtonChangeStatus->setText(q_("Stop"));
1020 	ui->pushButtonChangeStatus->setIcon(QIcon(":/graphicGui/uibtStop.png"));
1021         ui->pushButtonChangeStatus->setToolTip(q_("Stop the selected local telescope"));
1022 }
1023 
setStatusButtonToConnect()1024 void TelescopeDialog::setStatusButtonToConnect()
1025 {
1026         ui->pushButtonChangeStatus->setText(q_("Connect"));
1027 	ui->pushButtonChangeStatus->setIcon(QIcon(":/graphicGui/uibtStart.png"));
1028         ui->pushButtonChangeStatus->setToolTip(q_("Connect to the selected telescope"));
1029 }
1030 
setStatusButtonToDisconnect()1031 void TelescopeDialog::setStatusButtonToDisconnect()
1032 {
1033         ui->pushButtonChangeStatus->setText(q_("Disconnect"));
1034 	ui->pushButtonChangeStatus->setIcon(QIcon(":/graphicGui/uibtStop.png"));
1035         ui->pushButtonChangeStatus->setToolTip(q_("Disconnect from the selected telescope"));
1036 }
1037 
updateStyle()1038 void TelescopeDialog::updateStyle()
1039 {
1040 	if (dialog)
1041 	{
1042 		StelGui* gui = dynamic_cast<StelGui*>(StelApp::getInstance().getGui());
1043 		if (gui)
1044 			ui->textBrowserAbout->document()->setDefaultStyleSheet(gui->getStelStyle().htmlStyleSheet);
1045 	}
1046 }
1047 
checkBoxUseExecutablesToggled(bool useExecutables)1048 void TelescopeDialog::checkBoxUseExecutablesToggled(bool useExecutables)
1049 {
1050 	telescopeManager->setFlagUseServerExecutables(useExecutables);
1051 }
1052 
buttonBrowseServerDirectoryPressed()1053 void TelescopeDialog::buttonBrowseServerDirectoryPressed()
1054 {
1055 	QString newPath = QFileDialog::getExistingDirectory (Q_NULLPTR, QString(q_("Select a directory")), telescopeManager->getServerExecutablesDirectoryPath());
1056 	//TODO: Validation? Directory exists and contains servers?
1057 	if(!newPath.isEmpty())
1058 	{
1059 		ui->lineEditExecutablesDirectory->setText(newPath);
1060 		telescopeManager->setServerExecutablesDirectoryPath(newPath);
1061 		telescopeManager->setFlagUseServerExecutables(true);
1062 	}
1063 }
1064