1 /*
2  * Copyright (C) 2009 Timothy Reaves
3  * Copyright (C) 2011 Bogdan Marinov
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA  02110-1335, USA.
18  */
19 
20 #include "Oculars.hpp"
21 #include "OcularDialog.hpp"
22 #include "ui_ocularDialog.h"
23 
24 #include "StelApp.hpp"
25 #include "StelGui.hpp"
26 #include "StelFileMgr.hpp"
27 #include "StelModuleMgr.hpp"
28 #include "StelMainView.hpp"
29 #include "StelTranslator.hpp"
30 #include "StelActionMgr.hpp"
31 
32 #include <QAbstractItemModel>
33 #include <QDataWidgetMapper>
34 #include <QDebug>
35 #include <QFrame>
36 #include <QModelIndex>
37 #include <QSettings>
38 #include <QStandardItemModel>
39 #include <QMessageBox>
40 #include <limits>
41 #include <QRegularExpression>
42 
OcularDialog(Oculars * pluginPtr,QList<CCD * > * ccds,QList<Ocular * > * oculars,QList<Telescope * > * telescopes,QList<Lens * > * lenses)43 OcularDialog::OcularDialog(Oculars* pluginPtr,
44 			   QList<CCD *>* ccds,
45 			   QList<Ocular *>* oculars,
46 			   QList<Telescope *>* telescopes,
47 			   QList<Lens *> *lenses)
48 	: StelDialog("Oculars")
49 	, plugin(pluginPtr)
50 	, ccdMapper(Q_NULLPTR)
51 	, ocularMapper(Q_NULLPTR)
52 	, telescopeMapper(Q_NULLPTR)
53 	, lensMapper(Q_NULLPTR)
54 {
55 	ui = new Ui_ocularDialogForm;
56 	this->ccds = ccds;
57 	ccdTableModel = new PropertyBasedTableModel(this);
58 	CCD* ccdModel = CCD::ccdModel();
59 	ccdTableModel->init(reinterpret_cast<QList<QObject *>* >(ccds), ccdModel, ccdModel->propertyMap());
60 	this->oculars = oculars;
61 	ocularTableModel = new PropertyBasedTableModel(this);
62 	Ocular* ocularModel = Ocular::ocularModel();
63 	ocularTableModel->init(reinterpret_cast<QList<QObject *>* >(oculars), ocularModel, ocularModel->propertyMap());
64 	this->telescopes = telescopes;
65 	telescopeTableModel = new PropertyBasedTableModel(this);
66 	Telescope* telescopeModel = Telescope::telescopeModel();
67 	telescopeTableModel->init(reinterpret_cast<QList<QObject *>* >(telescopes), telescopeModel, telescopeModel->propertyMap());
68 
69 	this->lenses = lenses;
70 	lensTableModel = new PropertyBasedTableModel(this);
71 	Lens* lensModel = Lens::lensModel();
72 	lensTableModel->init(reinterpret_cast<QList<QObject *>* >(lenses),
73 			     lensModel,
74 			     lensModel->propertyMap());
75 
76 	QRegularExpression nameExp("^\\S.*");
77 	validatorName = new QRegularExpressionValidator(nameExp, this);
78 }
79 
~OcularDialog()80 OcularDialog::~OcularDialog()
81 {
82 	ocularTableModel->disconnect();
83 	telescopeTableModel->disconnect();
84 	ccdTableModel->disconnect();
85 	lensTableModel->disconnect();
86 
87 	delete ui;
88 	ui = Q_NULLPTR;
89 }
90 
91 /* ********************************************************************* */
92 #if 0
93 #pragma mark -
94 #pragma mark StelModule Methods
95 #endif
96 /* ********************************************************************* */
retranslate()97 void OcularDialog::retranslate()
98 {
99 	if (dialog) {
100 		ui->retranslateUi(dialog);
101 		initAboutText();
102 	}
103 }
104 
105 /* ********************************************************************* */
106 #if 0
107 #pragma mark -
108 #pragma mark Slot Methods
109 #endif
110 /* ********************************************************************* */
closeWindow()111 void OcularDialog::closeWindow()
112 {
113 	setVisible(false);
114 	StelMainView::getInstance().scene()->setActiveWindow(Q_NULLPTR);
115 }
116 
deleteSelectedCCD()117 void OcularDialog::deleteSelectedCCD()
118 {
119 	if (ccdTableModel->rowCount() == 1)
120 	{
121 		qDebug() << "Cannot delete the last entry.";
122 		QMessageBox::warning(&StelMainView::getInstance(), q_("Warning!"), q_("Cannot delete the last sensor."), QMessageBox::Ok);
123 		return;
124 	}
125 
126 	if (askConfirmation())
127 	{
128 		ccdTableModel->removeRows(ui->ccdListView->currentIndex().row(), 1);
129 		ui->ccdListView->setCurrentIndex(ccdTableModel->index(0, 1));
130 		plugin->updateLists();
131 	}
132 }
133 
deleteSelectedOcular()134 void OcularDialog::deleteSelectedOcular()
135 {
136 	if (ocularTableModel->rowCount() == 1)
137 	{
138 		qDebug() << "Cannot delete the last entry.";
139 		QMessageBox::warning(&StelMainView::getInstance(), q_("Warning!"), q_("Cannot delete the last ocular."), QMessageBox::Ok);
140 		return;
141 	}
142 
143 	if (askConfirmation())
144 	{
145 		ocularTableModel->removeRows(ui->ocularListView->currentIndex().row(), 1);
146 		ui->ocularListView->setCurrentIndex(ocularTableModel->index(0, 1));
147 		plugin->updateLists();
148 	}
149 }
150 
deleteSelectedTelescope()151 void OcularDialog::deleteSelectedTelescope()
152 {
153 	if (telescopeTableModel->rowCount() == 1)
154 	{
155 		qDebug() << "Cannot delete the last entry.";
156 		QMessageBox::warning(&StelMainView::getInstance(), q_("Warning!"), q_("Cannot delete the last telescope."), QMessageBox::Ok);
157 		return;
158 	}
159 
160 	if (askConfirmation())
161 	{
162 		telescopeTableModel->removeRows(ui->telescopeListView->currentIndex().row(), 1);
163 		ui->telescopeListView->setCurrentIndex(telescopeTableModel->index(0, 1));
164 		plugin->updateLists();
165 	}
166 }
167 
deleteSelectedLens()168 void OcularDialog::deleteSelectedLens()
169 {
170 	if (askConfirmation())
171 	{
172 		if (lensTableModel->rowCount() > 0)
173 		{
174 			lensTableModel->removeRows(ui->lensListView->currentIndex().row(), 1);
175 			if (lensTableModel->rowCount() > 0)
176 				ui->lensListView->setCurrentIndex(lensTableModel->index(0, 1));
177 
178 			plugin->updateLists();
179 		}
180 	}
181 }
182 
insertNewCCD()183 void OcularDialog::insertNewCCD()
184 {
185 	int count = ccdTableModel->rowCount();
186 	ccdTableModel->insertRows(count, 1);
187 	ui->ccdListView->setCurrentIndex(ccdTableModel->index(count, 1));
188 }
189 
insertNewOcular()190 void OcularDialog::insertNewOcular()
191 {
192 	int count = ocularTableModel->rowCount();
193 	ocularTableModel->insertRows(count, 1);
194 	ui->ocularListView->setCurrentIndex(ocularTableModel->index(count, 1));
195 }
196 
insertNewTelescope()197 void OcularDialog::insertNewTelescope()
198 {
199 	int count = telescopeTableModel->rowCount();
200 	telescopeTableModel->insertRows(count, 1);
201 	ui->telescopeListView->setCurrentIndex(telescopeTableModel->index(count, 1));
202 }
203 
insertNewLens()204 void OcularDialog::insertNewLens()
205 {
206 	int count = lensTableModel->rowCount();
207 	lensTableModel->insertRows(count, 1);
208 	ui->lensListView->setCurrentIndex(lensTableModel->index(count, 1));
209 }
210 
moveUpSelectedSensor()211 void OcularDialog::moveUpSelectedSensor()
212 {
213 	int index = ui->ccdListView->currentIndex().row();
214 	if (index > 0)
215 	{
216 		ccdTableModel->moveRowUp(index);
217 		plugin->updateLists();
218 	}
219 }
220 
moveUpSelectedOcular()221 void OcularDialog::moveUpSelectedOcular()
222 {
223 	int index = ui->ocularListView->currentIndex().row();
224 	if (index > 0)
225 	{
226 		ocularTableModel->moveRowUp(index);
227 		plugin->updateLists();
228 	}
229 }
230 
moveUpSelectedTelescope()231 void OcularDialog::moveUpSelectedTelescope()
232 {
233 	int index = ui->telescopeListView->currentIndex().row();
234 	if (index > 0)
235 	{
236 		telescopeTableModel->moveRowUp(index);
237 		plugin->updateLists();
238 	}
239 }
240 
moveUpSelectedLens()241 void OcularDialog::moveUpSelectedLens()
242 {
243 	int index = ui->lensListView->currentIndex().row();
244 	if (index > 0)
245 	{
246 		lensTableModel->moveRowUp(index);
247 		plugin->updateLists();
248 	}
249 }
250 
moveDownSelectedSensor()251 void OcularDialog::moveDownSelectedSensor()
252 {
253 	int index = ui->ccdListView->currentIndex().row();
254 	if (index >= 0 && index < ccdTableModel->rowCount() - 1)
255 	{
256 		ccdTableModel->moveRowDown(index);
257 		plugin->updateLists();
258 	}
259 }
260 
moveDownSelectedOcular()261 void OcularDialog::moveDownSelectedOcular()
262 {
263 	int index = ui->ocularListView->currentIndex().row();
264 	if (index >= 0 && index < ocularTableModel->rowCount() - 1)
265 	{
266 		ocularTableModel->moveRowDown(index);
267 		plugin->updateLists();
268 	}
269 }
270 
moveDownSelectedTelescope()271 void OcularDialog::moveDownSelectedTelescope()
272 {
273 	int index = ui->telescopeListView->currentIndex().row();
274 	if (index >= 0 && index < telescopeTableModel->rowCount() - 1)
275 	{
276 		telescopeTableModel->moveRowDown(index);
277 		plugin->updateLists();
278 	}
279 }
280 
moveDownSelectedLens()281 void OcularDialog::moveDownSelectedLens()
282 {
283 	int index = ui->lensListView->currentIndex().row();
284 	if (index >= 0 && index < lensTableModel->rowCount() - 1)
285 	{
286 		lensTableModel->moveRowDown(index);
287 		plugin->updateLists();
288 	}
289 }
290 
291 /* ********************************************************************* */
292 #if 0
293 #pragma mark -
294 #pragma mark Protected Methods
295 #endif
296 /* ********************************************************************* */
createDialogContent()297 void OcularDialog::createDialogContent()
298 {
299 	ui->setupUi(dialog);
300 	connect(&StelApp::getInstance(), SIGNAL(languageChanged()), this, SLOT(retranslate()));
301 	ui->ccdListView->setModel(ccdTableModel);
302 	ui->ocularListView->setModel(ocularTableModel);
303 	ui->telescopeListView->setModel(telescopeTableModel);
304 	ui->lensListView->setModel(lensTableModel);
305 
306 	// Kinetic scrolling
307 	kineticScrollingList << ui->textBrowser << ui->telescopeListView << ui->ccdListView << ui->ocularListView << ui->lensListView;
308 	StelGui* gui= dynamic_cast<StelGui*>(StelApp::getInstance().getGui());
309 	if (gui)
310 	{
311 		enableKineticScrolling(gui->getFlagUseKineticScrolling());
312 		connect(gui, SIGNAL(flagUseKineticScrollingChanged(bool)), this, SLOT(enableKineticScrolling(bool)));
313 	}
314 
315 	//Now the rest of the actions.
316 	connect(ui->closeStelWindow, SIGNAL(clicked()), this, SLOT(close()));
317 	connect(ui->TitleBar, SIGNAL(movedTo(QPoint)), this, SLOT(handleMovedTo(QPoint)));
318 
319 	connectBoolProperty(ui->checkBoxControlPanel,		"Oculars.flagGuiPanelEnabled");
320 	connectIntProperty(ui->guiFontSizeSpinBox,		"Oculars.guiPanelFontSize");
321 	connectBoolProperty(ui->checkBoxInitialFOV,		"Oculars.flagInitFOVUsage");
322 	connectBoolProperty(ui->checkBoxInitialDirection,	"Oculars.flagInitDirectionUsage");
323 	connectBoolProperty(ui->checkBoxResolutionCriterion,	"Oculars.flagShowResolutionCriteria");
324 	connectBoolProperty(ui->requireSelectionCheckBox,	"Oculars.flagRequireSelection");
325 	connectBoolProperty(ui->limitStellarMagnitudeCheckBox,	"Oculars.flagAutoLimitMagnitude");
326 	connectBoolProperty(ui->hideGridsLinesCheckBox,		"Oculars.flagHideGridsLines");
327 	connectBoolProperty(ui->scaleImageCircleCheckBox,	"Oculars.flagScaleImageCircle");
328 	connectBoolProperty(ui->semiTransparencyCheckBox,	"Oculars.flagSemiTransparency");
329 	connectIntProperty(ui->transparencySpinBox,	        "Oculars.transparencyMask");
330 	connectBoolProperty(ui->checkBoxDMSDegrees,		"Oculars.flagDMSDegrees");
331 	connectBoolProperty(ui->checkBoxTypeOfMount,		"Oculars.flagAutosetMountForCCD");
332 	connectBoolProperty(ui->checkBoxTelradFOVScaling,	"Oculars.flagScalingFOVForTelrad");
333 	connectBoolProperty(ui->checkBoxCCDFOVScaling,		"Oculars.flagScalingFOVForCCD");
334 	connectBoolProperty(ui->checkBoxToolbarButton,		"Oculars.flagShowOcularsButton");
335 	connectIntProperty(ui->arrowButtonScaleSpinBox,	        "Oculars.arrowButtonScale");
336 	connectBoolProperty(ui->checkBoxShowCcdCropOverlay,	"Oculars.flagShowCcdCropOverlay");
337 	connectBoolProperty(ui->checkBoxShowCcdCropOverlayPixelGrid,	"Oculars.flagShowCcdCropOverlayPixelGrid");
338 	connectIntProperty(ui->guiCcdCropOverlayHSizeSpinBox,	"Oculars.ccdCropOverlayHSize");
339 	connectIntProperty(ui->guiCcdCropOverlayVSizeSpinBox,	"Oculars.ccdCropOverlayVSize");
340 	connectBoolProperty(ui->contourCheckBox,		"Oculars.flagShowContour");
341 	connectBoolProperty(ui->cardinalsCheckBox,		"Oculars.flagShowCardinals");
342 	connectBoolProperty(ui->alignCrosshairCheckBox,		"Oculars.flagAlignCrosshair");
343 	connectColorButton(ui->textColorToolButton,             "Oculars.textColor", "text_color", "Oculars");
344 	connectColorButton(ui->lineColorToolButton,             "Oculars.lineColor", "line_color", "Oculars");
345 	connectColorButton(ui->focuserColorToolButton,		"Oculars.focuserColor", "focuser_color", "Oculars");
346 	connectBoolProperty(ui->checkBoxShowFocuserOverlay,	"Oculars.flagShowFocuserOverlay");
347 	connectBoolProperty(ui->checkBoxUseSmallFocuser,	"Oculars.flagUseSmallFocuserOverlay");
348 	connectBoolProperty(ui->checkBoxUseMediumFocuser,	"Oculars.flagUseMediumFocuserOverlay");
349 	connectBoolProperty(ui->checkBoxUseLargeFocuser,	"Oculars.flagUseLargeFocuserOverlay");
350 
351 	setupTelradFOVspins(plugin->getTelradFOV());
352 	connect(plugin, SIGNAL(telradFOVChanged(Vec4f)), this, SLOT(setupTelradFOVspins(Vec4f)));
353 	connect(ui->doubleSpinBoxTelradFOV1, SIGNAL(valueChanged(double)), this, SLOT(updateTelradCustomFOV()));
354 	connect(ui->doubleSpinBoxTelradFOV2, SIGNAL(valueChanged(double)), this, SLOT(updateTelradCustomFOV()));
355 	connect(ui->doubleSpinBoxTelradFOV3, SIGNAL(valueChanged(double)), this, SLOT(updateTelradCustomFOV()));
356 	connect(ui->doubleSpinBoxTelradFOV4, SIGNAL(valueChanged(double)), this, SLOT(updateTelradCustomFOV()));
357 	connect(ui->pushButtonRestoreTelradFOV, &QPushButton::clicked, this, [=] () { plugin->setTelradFOV(Vec4f(0.5f, 2.0f, 4.0f, 0.0f));} );
358 
359 	// The add & delete buttons
360 	connect(ui->addCCD,          SIGNAL(clicked()), this, SLOT(insertNewCCD()));
361 	connect(ui->deleteCCD,       SIGNAL(clicked()), this, SLOT(deleteSelectedCCD()));
362 	connect(ui->addOcular,       SIGNAL(clicked()), this, SLOT(insertNewOcular()));
363 	connect(ui->deleteOcular,    SIGNAL(clicked()), this, SLOT(deleteSelectedOcular()));
364 	connect(ui->addLens,         SIGNAL(clicked()), this, SLOT(insertNewLens()));
365 	connect(ui->deleteLens,      SIGNAL(clicked()), this, SLOT(deleteSelectedLens()));
366 	connect(ui->addTelescope,    SIGNAL(clicked()), this, SLOT(insertNewTelescope()));
367 	connect(ui->deleteTelescope, SIGNAL(clicked()), this, SLOT(deleteSelectedTelescope()));
368 
369 	// Validators
370 	ui->ccdName->setValidator(validatorName);
371 	ui->ocularName->setValidator(validatorName);
372 	ui->telescopeName->setValidator(validatorName);
373 	ui->lensName->setValidator(validatorName);
374 
375 	initAboutText();
376 
377 	connect(ui->pushButtonMoveOcularUp,      SIGNAL(pressed()), this, SLOT(moveUpSelectedOcular()));
378 	connect(ui->pushButtonMoveOcularDown,    SIGNAL(pressed()), this, SLOT(moveDownSelectedOcular()));
379 	connect(ui->pushButtonMoveSensorUp,      SIGNAL(pressed()), this, SLOT(moveUpSelectedSensor()));
380 	connect(ui->pushButtonMoveSensorDown,    SIGNAL(pressed()), this, SLOT(moveDownSelectedSensor()));
381 	connect(ui->pushButtonMoveTelescopeUp,   SIGNAL(pressed()), this, SLOT(moveUpSelectedTelescope()));
382 	connect(ui->pushButtonMoveTelescopeDown, SIGNAL(pressed()), this, SLOT(moveDownSelectedTelescope()));
383 	connect(ui->pushButtonMoveLensUp,        SIGNAL(pressed()), this, SLOT(moveUpSelectedLens()));
384 	connect(ui->pushButtonMoveLensDown,      SIGNAL(pressed()), this, SLOT(moveDownSelectedLens()));
385 
386 	// The CCD mapper
387 	ccdMapper = new QDataWidgetMapper();
388 	ccdMapper->setModel(ccdTableModel);
389 	ccdMapper->setSubmitPolicy(QDataWidgetMapper::AutoSubmit);
390 	ccdMapper->addMapping(ui->ccdName,       0);
391 	ccdMapper->addMapping(ui->ccdChipY,      1);
392 	ccdMapper->addMapping(ui->ccdChipX,      2);
393 	ccdMapper->addMapping(ui->ccdResX,       3);
394 	ccdMapper->addMapping(ui->ccdResY,       4);
395 	ccdMapper->addMapping(ui->ccdRotAngle,   5);
396 	ccdMapper->addMapping(ui->ccdBinningX,   6);
397 	ccdMapper->addMapping(ui->ccdBinningY,   7);
398 	ccdMapper->addMapping(ui->OAG_checkBox, 8);
399 	ccdMapper->addMapping(ui->OAGPrismH,    9);
400 	ccdMapper->addMapping(ui->OAGPrismW,    10);
401 	ccdMapper->addMapping(ui->OAGDist,      11);
402 	ccdMapper->addMapping(ui->OAGPrismPA,   12);
403 	ccdMapper->toFirst();
404 	connect(ui->ccdListView->selectionModel() , SIGNAL(currentRowChanged(QModelIndex, QModelIndex)),
405 		ccdMapper, SLOT(setCurrentModelIndex(QModelIndex)));
406 	connect(ui->ccdListView, SIGNAL(doubleClicked(QModelIndex)),
407 		     this, SLOT(selectCCD(QModelIndex)));
408 	ui->ccdListView->setSelectionBehavior(QAbstractItemView::SelectRows);
409 	int index = plugin->getSelectedCCDIndex();
410 	ui->ccdListView->setCurrentIndex(ccdTableModel->index(index>0 ? index : 0, 1));
411 
412 	connect(ui->ccdChipY,    SIGNAL(editingFinished()), this, SLOT(updateCCD()));
413 	connect(ui->ccdChipX,    SIGNAL(editingFinished()), this, SLOT(updateCCD()));
414 	connect(ui->ccdResX,     SIGNAL(editingFinished()), this, SLOT(updateCCD()));
415 	connect(ui->ccdResY,     SIGNAL(editingFinished()), this, SLOT(updateCCD()));
416 	connect(ui->ccdRotAngle, SIGNAL(editingFinished()), this, SLOT(updateCCD()));
417 	connect(ui->ccdBinningX, SIGNAL(editingFinished()), this, SLOT(updateCCD()));
418 	connect(ui->ccdBinningY, SIGNAL(editingFinished()), this, SLOT(updateCCD()));
419 	connect(ui->OAG_checkBox,SIGNAL(stateChanged(int)), this, SLOT(updateCCD()));
420 	connect(ui->OAGPrismH,   SIGNAL(editingFinished()), this, SLOT(updateCCD()));
421 	connect(ui->OAGPrismW,   SIGNAL(editingFinished()), this, SLOT(updateCCD()));
422 	connect(ui->OAGDist,     SIGNAL(editingFinished()), this, SLOT(updateCCD()));
423 	connect(ui->OAGPrismPA,  SIGNAL(editingFinished()), this, SLOT(updateCCD()));
424 	connect(plugin, SIGNAL(selectedCCDRotationAngleChanged(double)), this, SLOT(updateCCDRotationAngles()));
425 	connect(plugin, SIGNAL(selectedCCDPrismPositionAngleChanged(double)), this, SLOT(updateCCDRotationAngles()));
426 
427 	// The ocular mapper
428 	ocularMapper = new QDataWidgetMapper();
429 	ocularMapper->setModel(ocularTableModel);
430 	ocularMapper->setSubmitPolicy(QDataWidgetMapper::AutoSubmit);
431 	ocularMapper->addMapping(ui->ocularName,                 0);
432 	ocularMapper->addMapping(ui->ocularAFov,                 1);
433 	ocularMapper->addMapping(ui->ocularFL,                   2);
434 	ocularMapper->addMapping(ui->ocularFieldStop,            3);
435 	ocularMapper->addMapping(ui->binocularsCheckBox,         4, "checked");
436 	ocularMapper->addMapping(ui->permanentCrosshairCheckBox, 5, "checked");
437 	ocularMapper->toFirst();
438 	connect(ui->ocularListView->selectionModel() , SIGNAL(currentRowChanged(QModelIndex, QModelIndex)),
439 		ocularMapper, SLOT(setCurrentModelIndex(QModelIndex)));
440 	connect(ui->ocularListView, SIGNAL(doubleClicked(QModelIndex)),
441 		     this, SLOT(selectOcular(QModelIndex)));
442 	ui->ocularListView->setSelectionBehavior(QAbstractItemView::SelectRows);
443 	index = plugin->getSelectedOcularIndex();
444 	ui->ocularListView->setCurrentIndex(ocularTableModel->index(index>0 ? index : 0, 1));
445 
446 	// We need particular refresh methods to see immediate feedback.
447 	connect(ui->ocularAFov,                 SIGNAL(editingFinished()), this, SLOT(updateOcular()));
448 	connect(ui->ocularFL,                   SIGNAL(editingFinished()), this, SLOT(updateOcular()));
449 	connect(ui->ocularFieldStop,            SIGNAL(editingFinished()), this, SLOT(updateOcular()));
450 	connect(ui->binocularsCheckBox,         SIGNAL(stateChanged(int)), this, SLOT(updateOcular()));
451 	connect(ui->permanentCrosshairCheckBox, SIGNAL(stateChanged(int)), this, SLOT(updateOcular()));
452 
453 	// The lens mapper
454 	lensMapper = new QDataWidgetMapper();
455 	lensMapper->setModel(lensTableModel);
456 	lensMapper->setSubmitPolicy(QDataWidgetMapper::AutoSubmit);
457 	lensMapper->addMapping(ui->lensName,       0);
458 	lensMapper->addMapping(ui->lensMultiplier, 1);
459 	lensMapper->toFirst();
460 	connect(ui->lensListView->selectionModel(), SIGNAL(currentRowChanged(QModelIndex, QModelIndex)),
461 		lensMapper, SLOT(setCurrentModelIndex(QModelIndex)));
462 	connect(ui->lensListView, SIGNAL(doubleClicked(QModelIndex)),
463 		     this, SLOT(selectLens(QModelIndex)));
464 	ui->lensListView->setSelectionBehavior(QAbstractItemView::SelectRows);
465 	index = plugin->getSelectedLensIndex();
466 	ui->lensListView->setCurrentIndex(lensTableModel->index(index>0 ? index : 0, 1));
467 
468 	connect(ui->lensMultiplier, SIGNAL(editingFinished()), this, SLOT(updateLens()));
469 
470 	// The telescope mapper
471 	telescopeMapper = new QDataWidgetMapper();
472 	telescopeMapper->setModel(telescopeTableModel);
473 	telescopeMapper->setSubmitPolicy(QDataWidgetMapper::AutoSubmit);
474 	telescopeMapper->addMapping(ui->telescopeName,     0);
475 	telescopeMapper->addMapping(ui->telescopeDiameter, 1);
476 	telescopeMapper->addMapping(ui->telescopeFL,       2);
477 	telescopeMapper->addMapping(ui->telescopeHFlip,    3, "checked");
478 	telescopeMapper->addMapping(ui->telescopeVFlip,    4, "checked");
479 	telescopeMapper->addMapping(ui->telescopeEQ,       5, "checked");
480 	telescopeMapper->toFirst();
481 	connect(ui->telescopeListView->selectionModel() , SIGNAL(currentRowChanged(QModelIndex, QModelIndex)),
482 		telescopeMapper, SLOT(setCurrentModelIndex(QModelIndex)));
483 	connect(ui->telescopeListView, SIGNAL(doubleClicked(QModelIndex)),
484 		     this, SLOT(selectTelescope(QModelIndex)));
485 	ui->telescopeListView->setSelectionBehavior(QAbstractItemView::SelectRows);
486 	index = plugin->getSelectedTelescopeIndex();
487 	ui->telescopeListView->setCurrentIndex(telescopeTableModel->index(index>0 ? index : 0, 1));
488 
489 	connect(ui->telescopeDiameter, SIGNAL(editingFinished()), this, SLOT(updateTelescope()));
490 	connect(ui->telescopeFL,       SIGNAL(editingFinished()), this, SLOT(updateTelescope()));
491 	connect(ui->telescopeHFlip,    SIGNAL(stateChanged(int)), this, SLOT(updateTelescope()));
492 	connect(ui->telescopeVFlip,    SIGNAL(stateChanged(int)), this, SLOT(updateTelescope()));
493 	connect(ui->telescopeEQ,       SIGNAL(stateChanged(int)), this, SLOT(updateTelescope()));
494 
495 	connect(ui->binocularsCheckBox, SIGNAL(toggled(bool)), this, SLOT(setLabelsDescriptionText(bool)));
496 	connect(ui->checkBoxControlPanel, SIGNAL(toggled(bool)), this, SLOT(updateGuiOptions()));
497 	connect(ui->semiTransparencyCheckBox, SIGNAL(toggled(bool)), this, SLOT(updateGuiOptions()));
498 	connect(ui->checkBoxShowFocuserOverlay, SIGNAL(toggled(bool)), this, SLOT(updateGuiOptions()));
499 	connect(ui->checkBoxShowCcdCropOverlay, SIGNAL(toggled(bool)), this, SLOT(updateGuiOptions()));
500 	setLabelsDescriptionText(ui->binocularsCheckBox->isChecked());
501 	updateGuiOptions();
502 }
503 
setupTelradFOVspins(Vec4f fov)504 void OcularDialog::setupTelradFOVspins(Vec4f fov)
505 {
506 	ui->doubleSpinBoxTelradFOV1->setValue(static_cast<double>(fov[0]));
507 	ui->doubleSpinBoxTelradFOV2->setValue(static_cast<double>(fov[1]));
508 	ui->doubleSpinBoxTelradFOV3->setValue(static_cast<double>(fov[2]));
509 	ui->doubleSpinBoxTelradFOV4->setValue(static_cast<double>(fov[3]));
510 }
511 
updateCCDRotationAngles()512 void OcularDialog::updateCCDRotationAngles()
513 {
514 	if (dialog->isVisible())
515 	{
516 		if (plugin->getSelectedCCDIndex()==ccdMapper->currentIndex())
517 		{
518 			ui->ccdRotAngle->setValue(plugin->getSelectedCCDRotationAngle());
519 			ui->OAGPrismPA->setValue(plugin->getSelectedCCDPrismPositionAngle());
520 		}
521 	}
522 }
523 
updateTelradCustomFOV()524 void OcularDialog::updateTelradCustomFOV()
525 {
526 	Vec4f fov(static_cast<float>(ui->doubleSpinBoxTelradFOV1->value()),
527 		  static_cast<float>(ui->doubleSpinBoxTelradFOV2->value()),
528 		  static_cast<float>(ui->doubleSpinBoxTelradFOV3->value()),
529 		  static_cast<float>(ui->doubleSpinBoxTelradFOV4->value()));
530 	plugin->setTelradFOV(fov);
531 }
532 
533 // We need particular refresh methods to see immediate feedback.
updateOcular()534 void OcularDialog::updateOcular()
535 {
536 	ocularMapper->submit();
537 	plugin->selectOcularAtIndex(plugin->getSelectedOcularIndex());
538 }
539 
selectOcular(const QModelIndex)540 void OcularDialog::selectOcular(const QModelIndex)
541 {
542 	plugin->selectOcularAtIndex(ocularMapper->currentIndex());
543 	plugin->updateLists();
544 }
545 
updateLens()546 void OcularDialog::updateLens()
547 {
548 	lensMapper->submit();
549 	plugin->selectLensAtIndex(plugin->getSelectedLensIndex());
550 }
551 
selectLens(const QModelIndex)552 void OcularDialog::selectLens(const QModelIndex)
553 {
554 	plugin->selectLensAtIndex(lensMapper->currentIndex());
555 	plugin->updateLists();
556 }
557 
updateCCD()558 void OcularDialog::updateCCD()
559 {
560 	ccdMapper->submit();
561 	plugin->selectCCDAtIndex(plugin->getSelectedCCDIndex());
562 }
563 
selectCCD(const QModelIndex)564 void OcularDialog::selectCCD(const QModelIndex)
565 {
566 	plugin->selectCCDAtIndex(ccdMapper->currentIndex());
567 	plugin->updateLists();
568 }
569 
updateTelescope()570 void OcularDialog::updateTelescope()
571 {
572 	telescopeMapper->submit();
573 	plugin->selectTelescopeAtIndex(plugin->getSelectedTelescopeIndex());
574 }
575 
selectTelescope(const QModelIndex)576 void OcularDialog::selectTelescope(const QModelIndex)
577 {
578 	plugin->selectTelescopeAtIndex(telescopeMapper->currentIndex());
579 	plugin->updateLists();
580 }
581 
setLabelsDescriptionText(bool state)582 void OcularDialog::setLabelsDescriptionText(bool state)
583 {
584 	if (state)
585 	{
586 		// TRANSLATORS: tFOV for binoculars (tFOV = True Field of View)
587 		ui->labelFOV->setText(q_("tFOV:"));
588 		// TRANSLATORS: Magnification factor for binoculars
589 		ui->labelFL->setText(q_("Magnification factor:"));
590 		ui->labelFS->setText(q_("Diameter:"));
591 	}
592 	else
593 	{
594 		ui->labelFOV->setText(q_("aFOV:"));
595 		ui->labelFL->setText(q_("Focal length:"));
596 		ui->labelFS->setText(q_("Field stop:"));
597 	}
598 }
599 
initAboutText()600 void OcularDialog::initAboutText()
601 {
602 	//BM: Most of the text for now is the original contents of the About widget.
603 	QString html = "<html><head><title></title></head><body>";
604 
605 	html += "<h2>" + q_("Oculars Plug-in") + "</h2><table width=\"90%\">";
606 	html += "<tr width=\"30%\"><td><strong>" + q_("Version") + ":</strong></td><td>" + OCULARS_PLUGIN_VERSION + "</td></tr>";
607 	html += "<tr><td><strong>" + q_("License") + ":</strong></td><td>" + OCULARS_PLUGIN_LICENSE + "</td></tr>";
608 	html += "<tr><td><strong>" + q_("Author") + ":</strong></td><td>Timothy Reaves &lt;treaves@silverfieldstech.com&gt;</td></tr>";
609 	html += "<tr><td rowspan=\"7\"><strong>" + q_("Contributors") + ":</strong></td><td>Bogdan Marinov</td></tr>";
610 	html += "<tr><td>Alexander Wolf</td></tr>";
611 	html += "<tr><td>Georg Zotti</td></tr>";
612 	html += "<tr><td>Rumen G. Bogdanovski &lt;rumen@skyarchive.org&gt;</td></tr>";
613 	html += "<tr><td>Pawel Stolowski (" + q_("Barlow lens feature") + ")</td></tr>";
614 	html += "<tr><td>Matt Hughes (" + q_("Sensor crop overlay feature") + ")</td></tr>";
615 	html += "<tr><td>Dhia Moakhar (" + q_("Pixel grid feature") + ")</td></tr>";
616 	html += "</table>";
617 
618 	// Overview
619 	html += "<h3>" + q_("Overview") + "</h3>";
620 
621 	html += "<p>" + q_("This plugin is intended to simulate what you would see through an eyepiece.  This configuration dialog can be used to add, modify, or delete eyepieces and telescopes, as well as CCD Sensors.  Your first time running the app will populate some samples to get you started.") + "</p>";
622 	html += "<p>" + q_("You can choose to scale the image you see on the screen.") + " ";
623 	html +=         q_("This is intended to show you a better comparison of what one eyepiece/telescope combination will be like when compared to another.") + " ";
624 	html +=         q_("The same eyepiece in two different telescopes of differing focal length will produce two different exit pupils, changing the view somewhat.") + " ";
625 	html +=         q_("The trade-off of this is that, with the image scaled, a large part of the screen can be wasted.") + " ";
626 	html +=         q_("Therefore we recommend that you leave it off, unless you feel you have a need for it.") + "</p>";
627 	html += "<p>" + q_("You can toggle a crosshair in the view.") + "</p>";
628 	html += "<p>" + QString(q_("You can toggle a Telrad finder. This feature draws three concentric circles of 0.5%1, 2.0%1, and 4.0%1, helping you see what you would expect to see with the naked eye through the Telrad (or similar) finder.")).arg(QChar(0x00B0));
629 	html +=         q_("You can adjust the diameters or even add a fourth circle if you have a different finder, or revert to the Telrad standard sizes.") + "</p>";
630 	html += "<p>" + q_("If you find any issues, please let me know. Enjoy!") + "</p>";
631 
632 	// Keys
633 	html += "<h3>" + q_("Hot Keys") + "</h3>";
634 	html += "<p>" + q_("The plug-in's key bindings can be edited in the Keyboard shortcuts editor (F7).") + "</p>";
635 
636 	// Notes
637 	html += "<h3>" + q_("Notes") + "</h3>";
638 	html += "<p>" +  q_("The sensor view has a feature to show a sensor crop overlay with information about the crop size. The size of this rectangle may be adjusted when binning is active (e.g. crop size of 100px will be adjusted to 99px by binning 3).") + " ";
639 	html +=          q_("In this case, information about crop size overlay will be marked by %1.").arg("[*]") + " ";
640 	html +=          q_("This mark is also displayed if the crop size is larger than the sensor size.") + "</p>";
641 
642 	html += StelApp::getInstance().getModuleMgr().getStandardSupportLinksInfo("Oculars plugin");
643 	html += "</body></html>";
644 
645 	StelGui* gui = dynamic_cast<StelGui*>(StelApp::getInstance().getGui());
646 	if (gui)
647 		ui->textBrowser->document()->setDefaultStyleSheet(QString(gui->getStelStyle().htmlStyleSheet));
648 
649 	ui->textBrowser->setHtml(html);
650 }
651 
updateGuiOptions()652 void OcularDialog::updateGuiOptions()
653 {
654 	bool flag = ui->checkBoxControlPanel->isChecked();
655 	ui->guiFontSizeLabel->setEnabled(flag);
656 	ui->guiFontSizeSpinBox->setEnabled(flag);
657 
658 	ui->transparencySpinBox->setEnabled(ui->semiTransparencyCheckBox->isChecked());
659 
660 	flag = ui->checkBoxShowFocuserOverlay->isChecked();
661 	ui->labelFocuserOverlay->setEnabled(flag);
662 	ui->checkBoxUseSmallFocuser->setEnabled(flag);
663 	ui->checkBoxUseMediumFocuser->setEnabled(flag);
664 	ui->checkBoxUseLargeFocuser->setEnabled(flag);
665 
666 	flag = ui->checkBoxShowCcdCropOverlay->isChecked();
667 	ui->guiCcdCropOverlaySizeLabel->setEnabled(flag);
668 	ui->guiCcdCropOverlayHSizeSpinBox->setEnabled(flag);
669 	ui->guiCcdCropOverlayVSizeSpinBox->setEnabled(flag);
670 	ui->checkBoxShowCcdCropOverlayPixelGrid->setEnabled(flag);
671 }
672 
673