1 /*
2 SPDX-FileCopyrightText: 2002 Pablo de Vicente <vicente@oan.es>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7 #include "modcalcsidtime.h"
8
9 #include "kstarsdata.h"
10 #include "kstarsdatetime.h"
11 #include "ksnotification.h"
12 #include "dialogs/locationdialog.h"
13
14 #include <KLineEdit>
15
16 #include <QTextStream>
17
modCalcSidTime(QWidget * parent)18 modCalcSidTime::modCalcSidTime(QWidget *parent) : QFrame(parent)
19 {
20 setupUi(this);
21
22 //Preset date and location
23 showCurrentTimeAndLocation();
24
25 // signals and slots connections
26 connect(LocationButton, SIGNAL(clicked()), this, SLOT(slotChangeLocation()));
27 connect(Date, SIGNAL(dateChanged(QDate)), this, SLOT(slotChangeDate()));
28 connect(LT, SIGNAL(timeChanged(QTime)), this, SLOT(slotConvertST(QTime)));
29 connect(ST, SIGNAL(timeChanged(QTime)), this, SLOT(slotConvertLT(QTime)));
30
31 connect(LocationCheckBatch, SIGNAL(clicked()), this, SLOT(slotLocationChecked()));
32 connect(DateCheckBatch, SIGNAL(clicked()), this, SLOT(slotDateChecked()));
33 connect(LocationCheckBatch, SIGNAL(clicked()), this, SLOT(slotHelpLabel()));
34 connect(DateCheckBatch, SIGNAL(clicked()), this, SLOT(slotHelpLabel()));
35 connect(ComputeComboBatch, SIGNAL(currentIndexChanged(int)), this, SLOT(slotHelpLabel()));
36
37 connect(InputFileBatch, SIGNAL(urlSelected(QUrl)), this, SLOT(slotCheckFiles()));
38 connect(OutputFileBatch, SIGNAL(urlSelected(QUrl)), this, SLOT(slotCheckFiles()));
39 connect(LocationButtonBatch, SIGNAL(clicked()), this, SLOT(slotLocationBatch()));
40 connect(RunButtonBatch, SIGNAL(clicked()), this, SLOT(slotRunBatch()));
41 connect(ViewButtonBatch, SIGNAL(clicked()), this, SLOT(slotViewBatch()));
42
43 RunButtonBatch->setEnabled(false);
44 ViewButtonBatch->setEnabled(false);
45
46 show();
47 }
48
showCurrentTimeAndLocation()49 void modCalcSidTime::showCurrentTimeAndLocation()
50 {
51 KStarsData *data = KStarsData::Instance();
52 LT->setTime(data->lt().time());
53 Date->setDate(data->lt().date());
54
55 geo = data->geo();
56 LocationButton->setText(geo->fullName());
57 geoBatch = data->geo();
58 LocationButtonBatch->setText(geoBatch->fullName());
59
60 slotConvertST(LT->time());
61 }
62
slotChangeLocation()63 void modCalcSidTime::slotChangeLocation()
64 {
65 QPointer<LocationDialog> ld = new LocationDialog(this);
66
67 if (ld->exec() == QDialog::Accepted)
68 {
69 GeoLocation *newGeo = ld->selectedCity();
70 if (newGeo)
71 {
72 geo = newGeo;
73 LocationButton->setText(geo->fullName());
74
75 //Update the displayed ST
76 slotConvertST(LT->time());
77 }
78 }
79 delete ld;
80 }
81
slotChangeDate()82 void modCalcSidTime::slotChangeDate()
83 {
84 slotConvertST(LT->time());
85 }
86
slotConvertST(const QTime & lt)87 void modCalcSidTime::slotConvertST(const QTime <)
88 {
89 // blockSignals is used to break signal loop
90 ST->blockSignals(true);
91 ST->setTime(computeLTtoST(lt));
92 ST->blockSignals(false);
93 }
94
slotConvertLT(const QTime & st)95 void modCalcSidTime::slotConvertLT(const QTime &st)
96 {
97 // blockSignals is used to break signal loop
98 LT->blockSignals(true);
99 LT->setTime(computeSTtoLT(st));
100 LT->blockSignals(false);
101 }
102
computeLTtoST(QTime lt)103 QTime modCalcSidTime::computeLTtoST(QTime lt)
104 {
105 KStarsDateTime utdt = geo->LTtoUT(KStarsDateTime(Date->date(), lt));
106 dms st = geo->GSTtoLST(utdt.gst());
107 return QTime(st.hour(), st.minute(), st.second());
108 }
109
computeSTtoLT(QTime st)110 QTime modCalcSidTime::computeSTtoLT(QTime st)
111 {
112 KStarsDateTime dt0 = KStarsDateTime(Date->date(), QTime(0, 0, 0));
113 dms lst;
114 lst.setH(st.hour(), st.minute(), st.second());
115 dms gst = geo->LSTtoGST(lst);
116 return geo->UTtoLT(KStarsDateTime(Date->date(), dt0.GSTtoUT(gst))).time();
117 }
118
119 //** Batch mode **//
slotDateChecked()120 void modCalcSidTime::slotDateChecked()
121 {
122 DateBatch->setEnabled(!DateCheckBatch->isChecked());
123 }
124
slotLocationChecked()125 void modCalcSidTime::slotLocationChecked()
126 {
127 LocationButtonBatch->setEnabled(!LocationCheckBatch->isChecked());
128
129 if (LocationCheckBatch->isChecked())
130 {
131 QString message = i18n("Location strings consist of the "
132 "comma-separated names of the city, province and country. "
133 "If the string contains spaces, enclose it in quotes so it "
134 "gets parsed properly.");
135
136 KMessageBox::information(nullptr, message, i18n("Hint for writing location strings"),
137 "DontShowLocationStringMessageBox");
138 }
139 }
140
slotHelpLabel()141 void modCalcSidTime::slotHelpLabel()
142 {
143 QStringList inList;
144 if (ComputeComboBatch->currentIndex() == 0)
145 inList.append(i18n("local time"));
146 else
147 inList.append(i18n("sidereal time"));
148
149 if (DateCheckBatch->checkState() == Qt::Checked)
150 inList.append(i18n("date"));
151
152 if (LocationCheckBatch->checkState() == Qt::Checked)
153 inList.append(i18n("location"));
154
155 QString inListString = inList[0];
156 if (inList.size() == 2)
157 inListString = i18n("%1 and %2", inList[0], inList[1]);
158 if (inList.size() == 3)
159 inListString = i18n("%1, %2 and %3", inList[0], inList[1], inList[2]);
160
161 HelpLabel->setText(i18n("Specify %1 in the input file.", inListString));
162 }
163
slotLocationBatch()164 void modCalcSidTime::slotLocationBatch()
165 {
166 QPointer<LocationDialog> ld = new LocationDialog(this);
167
168 if (ld->exec() == QDialog::Accepted)
169 {
170 GeoLocation *newGeo = ld->selectedCity();
171 if (newGeo)
172 {
173 geoBatch = newGeo;
174 LocationButtonBatch->setText(geoBatch->fullName());
175 }
176 }
177 delete ld;
178 }
179
slotCheckFiles()180 void modCalcSidTime::slotCheckFiles()
181 {
182 if (!InputFileBatch->lineEdit()->text().isEmpty() && !OutputFileBatch->lineEdit()->text().isEmpty())
183 {
184 RunButtonBatch->setEnabled(true);
185 }
186 else
187 {
188 RunButtonBatch->setEnabled(false);
189 }
190 }
191
slotRunBatch()192 void modCalcSidTime::slotRunBatch()
193 {
194 QString inputFileName = InputFileBatch->url().toLocalFile();
195
196 if (QFile::exists(inputFileName))
197 {
198 QFile f(inputFileName);
199 if (!f.open(QIODevice::ReadOnly))
200 {
201 QString message = i18n("Could not open file %1.", f.fileName());
202 KSNotification::sorry(message, i18n("Could Not Open File"));
203 inputFileName.clear();
204 return;
205 }
206
207 QTextStream istream(&f);
208 processLines(istream);
209
210 ViewButtonBatch->setEnabled(true);
211
212 f.close();
213 }
214 else
215 {
216 QString message = i18n("Invalid file: %1", inputFileName);
217 KSNotification::sorry(message, i18n("Invalid file"));
218 inputFileName.clear();
219 return;
220 }
221 }
222
processLines(QTextStream & istream)223 void modCalcSidTime::processLines(QTextStream &istream)
224 {
225 QFile fOut(OutputFileBatch->url().toLocalFile());
226 fOut.open(QIODevice::WriteOnly);
227 QTextStream ostream(&fOut);
228
229 QString line;
230 dms LST;
231 QTime inTime, outTime;
232 QDate dt;
233
234 if (!DateCheckBatch->isChecked())
235 dt = DateBatch->date();
236
237 while (!istream.atEnd())
238 {
239 line = istream.readLine();
240 line = line.trimmed();
241
242 QStringList fields = line.split(' ', QString::SkipEmptyParts);
243
244 //Find and parse the location string
245 if (LocationCheckBatch->isChecked())
246 {
247 //First, look for a pair of quotation marks, and parse the string between them
248 QChar q = '\"';
249 if (line.indexOf(q) == -1)
250 q = '\'';
251 if (line.count(q) == 2)
252 {
253 int iStart = line.indexOf(q);
254 int iEnd = line.indexOf(q, iStart + 1);
255 QString locationString = line.mid(iStart, iEnd - iStart + 1);
256 line.remove(locationString);
257 fields = line.split(' ', QString::SkipEmptyParts);
258 locationString.remove(q);
259
260 QStringList locationFields = locationString.split(',', QString::SkipEmptyParts);
261 for (int i = 0; i < locationFields.size(); i++)
262 locationFields[i] = locationFields[i].trimmed();
263
264 if (locationFields.size() == 1)
265 locationFields.insert(1, "");
266 if (locationFields.size() == 2)
267 locationFields.insert(1, "");
268 if (locationFields.size() != 3)
269 {
270 qDebug() << "Error: could not parse location string: " << locationString;
271 continue;
272 }
273
274 geoBatch = KStarsData::Instance()->locationNamed(locationFields[0], locationFields[1],
275 locationFields[2]);
276 if (geoBatch == nullptr)
277 {
278 qDebug() << "Error: location not found in database: " << locationString;
279 continue;
280 }
281 }
282 }
283
284 if (DateCheckBatch->isChecked())
285 {
286 //Parse one of the fields as the date
287 for (auto &s : fields)
288 {
289 dt = QDate::fromString(s);
290 if (dt.isValid())
291 break;
292 }
293 if (!dt.isValid())
294 {
295 qDebug() << "Error: did not find a valid date string in: " << line;
296 continue;
297 }
298 }
299
300 //Parse one of the fields as the time
301 for (auto &s : fields)
302 {
303 if (s.contains(':'))
304 {
305 inTime = QTime::fromString(s.length() == 4 ? '0' + s : s);
306 if (inTime.isValid())
307 break;
308 }
309 }
310 if (!inTime.isValid())
311 {
312 qDebug() << "Error: did not find a valid time string in: " << line;
313 continue;
314 }
315
316 if (geoBatch != nullptr)
317 {
318 if (ComputeComboBatch->currentIndex() == 0)
319 {
320 //inTime is the local time, compute LST
321 KStarsDateTime ksdt(dt, inTime);
322 ksdt = geoBatch->LTtoUT(ksdt);
323 dms lst = geoBatch->GSTtoLST(ksdt.gst());
324 outTime = QTime(lst.hour(), lst.minute(), lst.second());
325 }
326 else
327 {
328 //inTime is the sidereal time, compute the local time
329 KStarsDateTime ksdt(dt, QTime(0, 0, 0));
330 dms lst;
331 lst.setH(inTime.hour(), inTime.minute(), inTime.second());
332 QTime ut = ksdt.GSTtoUT(geoBatch->LSTtoGST(lst));
333 ksdt.setTime(ut);
334 ksdt = geoBatch->UTtoLT(ksdt);
335 outTime = ksdt.time();
336 }
337
338 //Write to output file
339 ostream << QLocale().toString(dt, QLocale::LongFormat) << " \"" << geoBatch->fullName() << "\" "
340 << QLocale().toString(inTime) << " " << QLocale().toString(outTime) << '\n';
341 }
342 }
343
344 fOut.close();
345 }
346
slotViewBatch()347 void modCalcSidTime::slotViewBatch()
348 {
349 QFile fOut(OutputFileBatch->url().toLocalFile());
350 fOut.open(QIODevice::ReadOnly);
351 QTextStream istream(&fOut);
352 QStringList text;
353
354 while (!istream.atEnd())
355 text.append(istream.readLine());
356
357 fOut.close();
358
359 KMessageBox::informationList(nullptr, i18n("Results of Sidereal time calculation"), text,
360 OutputFileBatch->url().toLocalFile());
361 }
362