/* * Time zone configuration plug-in for Stellarium * * Copyright (C) 2010 Bogdan Marinov * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "TimeZoneConfigurationWindow.hpp" #include "DefineTimeZoneWindow.hpp" #include "ui_defineTimeZone.h" #include "StelApp.hpp" #include "StelTranslator.hpp" #include #include DefineTimeZoneWindow::DefineTimeZoneWindow() { ui = new Ui_defineTimeZoneForm(); timeZoneNameValidator = new QRegExpValidator(QRegExp("[^:\\d,+-/]{3,}"), this); } DefineTimeZoneWindow::~DefineTimeZoneWindow() { delete ui; delete timeZoneNameValidator; } void DefineTimeZoneWindow::retranslate() { if (dialog) { ui->retranslateUi(dialog); int startDateMonthIndex = ui->comboBoxDstStartDateMonth->currentIndex(); int startDayIndex = ui->comboBoxDstStartDay->currentIndex(); int startMonthIndex = ui->comboBoxDstStartMonth->currentIndex(); int startWeekIndex = ui->comboBoxDstStartWeek->currentIndex(); int endDateMonthIndex = ui->comboBoxDstEndDateMonth->currentIndex(); int endDayIndex = ui->comboBoxDstEndDay->currentIndex(); int endMonthIndex = ui->comboBoxDstEndMonth->currentIndex(); int endWeekIndex = ui->comboBoxDstEndWeek->currentIndex(); populateDateLists(); ui->comboBoxDstStartDateMonth->setCurrentIndex(startDateMonthIndex); ui->comboBoxDstStartDay->setCurrentIndex(startDayIndex); ui->comboBoxDstStartMonth->setCurrentIndex(startMonthIndex); ui->comboBoxDstStartWeek->setCurrentIndex(startWeekIndex); ui->comboBoxDstEndDateMonth->setCurrentIndex(endDateMonthIndex); ui->comboBoxDstEndDay->setCurrentIndex(endDayIndex); ui->comboBoxDstEndMonth->setCurrentIndex(endMonthIndex); ui->comboBoxDstEndWeek->setCurrentIndex(endWeekIndex); } } void DefineTimeZoneWindow::createDialogContent() { ui->setupUi(dialog); connect(&StelApp::getInstance(), SIGNAL(languageChanged()), this, SLOT(retranslate())); connect(ui->closeStelWindow, SIGNAL(clicked()), this, SLOT(close())); connect(ui->pushButtonUseDefinition, SIGNAL(clicked()), this, SLOT(useDefinition())); connect(ui->doubleSpinBoxOffset, SIGNAL(valueChanged(double)), this, SLOT(updateDstOffset(double))); connect(ui->comboBoxDstStartDateMonth, SIGNAL(currentIndexChanged(int)), this, SLOT(updateDayNumberMaximumDstStart(int))); connect(ui->comboBoxDstEndDateMonth, SIGNAL(currentIndexChanged(int)), this, SLOT(updateDayNumberMaximumDstEnd(int))); ui->lineEditName->setValidator(timeZoneNameValidator); ui->lineEditNameDst->setValidator(timeZoneNameValidator); resetWindowState(); } void DefineTimeZoneWindow::useDefinition() { QString definition; QString timeZoneName = ui->lineEditName->text(); if (timeZoneName.length() < 3) { return; } definition.append(timeZoneName); definition.append(TimeZoneConfigurationWindow::getTzOffsetStringFrom(ui->doubleSpinBoxOffset)); //Daylight saving time if (ui->checkBoxDst->isChecked()) { QString dstTimeZoneName = ui->lineEditNameDst->text(); if (dstTimeZoneName.length() < 3 || dstTimeZoneName == timeZoneName) { return; } //The name is the minimum required for DST definition.append(dstTimeZoneName); //The offset is not necessary if (ui->checkBoxOffsetDst->isChecked()) { definition.append(TimeZoneConfigurationWindow::getTzOffsetStringFrom(ui->doubleSpinBoxOffsetDst)); } if (ui->groupBoxDstStart->isChecked() && ui->groupBoxDstEnd->isChecked()) { if (ui->radioButtonDstStartDate->isChecked()) { const int month = ui->comboBoxDstStartDateMonth->currentIndex() + 1; const int day = ui->spinBoxDstStartDateDay->value(); QDate startDate; if (month == 2 && day == 29) { //Leap year: day is indexed between 0 and 365 startDate.setDate(2000, month, day); definition.append(QString(",%1").arg(startDate.dayOfYear() - 1)); } else { startDate.setDate(2010, month, day); definition.append(QString(",J%1").arg(startDate.dayOfYear())); } } else //Day of week { //Day of the week: 0-6, 0 is Sunday int day = ui->comboBoxDstStartDay->currentIndex(); //Week ordinal number: 1-5, 5 is "last" int week = ui->comboBoxDstStartWeek->currentIndex() + 1; //Month: 1-12 int month = ui->comboBoxDstStartMonth->currentIndex() + 1; definition.append(QString(",M%1.%2.%3").arg(month).arg(week).arg(day)); } if (ui->checkBoxDstStartTime->isChecked()) { definition.append(ui->timeEditDstStart->time().toString("'/'hh:mm:ss")); } if (ui->radioButtonDstEndDate->isChecked()) { const int month = ui->comboBoxDstEndDateMonth->currentIndex() + 1; const int day = ui->spinBoxDstEndDateDay->value(); QDate endDate; if (month == 2 && day == 29) { //Leap year: day is indexed between 0 and 365 endDate.setDate(2000, month, day); definition.append(QString(",%1").arg(endDate.dayOfYear() - 1)); } else { endDate.setDate(2010, month, day); definition.append(QString(",J%1").arg(endDate.dayOfYear())); } } else //Day of week { //Day of the week: 0-6, 0 is Sunday int day = ui->comboBoxDstEndDay->currentIndex(); //Week ordinal number: 1-5, 5 is "last" int week = ui->comboBoxDstEndWeek->currentIndex() + 1; //Month: 1-12 int month = ui->comboBoxDstEndMonth->currentIndex() + 1; definition.append(QString(",M%1.%2.%3").arg(month).arg(week).arg(day)); } if (ui->checkBoxDstEndTime->isChecked()) { definition.append(ui->timeEditDstEnd->time().toString("'/'hh:mm:ss")); } } } emit timeZoneDefined(definition); close(); } void DefineTimeZoneWindow::updateDstOffset(double normalOffset) { if (ui->checkBoxOffsetDst->isChecked()) return; //By default, the DST offset is +1 hour the normal offset ui->doubleSpinBoxOffsetDst->setValue(normalOffset + 1.0); } void DefineTimeZoneWindow::resetWindowState() { populateDateLists(); //Default section ui->lineEditName->clear(); ui->lineEditNameDst->clear(); ui->doubleSpinBoxOffset->setValue(0.0); //(indirectly sets doubleSpinBoxOffsetDst) ui->checkBoxDst->setChecked(false); ui->frameDst->setVisible(false); ui->checkBoxOffsetDst->setChecked(false); ui->doubleSpinBoxOffsetDst->setEnabled(false); ui->groupBoxDstStart->setChecked(false); //(indirectly sets the other one) ui->radioButtonDstStartDay->setChecked(true); ui->radioButtonDstEndDay->setChecked(true); ui->spinBoxDstStartDateDay->setValue(1); ui->spinBoxDstEndDateDay->setValue(1); ui->comboBoxDstStartDateMonth->setCurrentIndex(0); ui->comboBoxDstEndDateMonth->setCurrentIndex(0); ui->checkBoxDstStartTime->setChecked(false); ui->timeEditDstStart->setEnabled(false); ui->timeEditDstStart->setTime(QTime(2, 0, 0, 0)); ui->checkBoxDstEndTime->setChecked(false); ui->timeEditDstEnd->setEnabled(false); ui->timeEditDstEnd->setTime(QTime(2, 0, 0, 0)); } void DefineTimeZoneWindow::populateDateLists() { QStringList monthList; monthList.append(q_("January")); monthList.append(q_("February")); monthList.append(q_("March")); monthList.append(q_("April")); monthList.append(q_("May")); monthList.append(q_("June")); monthList.append(q_("July")); monthList.append(q_("August")); monthList.append(q_("September")); monthList.append(q_("October")); monthList.append(q_("November")); monthList.append(q_("December")); ui->comboBoxDstStartMonth->clear(); ui->comboBoxDstStartMonth->addItems(monthList); ui->comboBoxDstEndMonth->clear(); ui->comboBoxDstEndMonth->addItems(monthList); ui->comboBoxDstStartDateMonth->clear(); ui->comboBoxDstStartDateMonth->addItems(monthList); ui->comboBoxDstEndDateMonth->clear(); ui->comboBoxDstEndDateMonth->addItems(monthList); QStringList weekList; weekList.append(q_("First week")); weekList.append(q_("Second week")); weekList.append(q_("Third week")); weekList.append(q_("Fourth week")); weekList.append(q_("Last week")); ui->comboBoxDstStartWeek->clear(); ui->comboBoxDstStartWeek->addItems(weekList); ui->comboBoxDstEndWeek->clear(); ui->comboBoxDstEndWeek->addItems(weekList); //Starts from Sunday deliberately QStringList dayList; dayList.append(q_("Sunday")); dayList.append(q_("Monday")); dayList.append(q_("Tuesday")); dayList.append(q_("Wednesday")); dayList.append(q_("Thursday")); dayList.append(q_("Friday")); dayList.append(q_("Saturday")); ui->comboBoxDstStartDay->clear(); ui->comboBoxDstStartDay->addItems(dayList); ui->comboBoxDstEndDay->clear(); ui->comboBoxDstEndDay->addItems(dayList); } void DefineTimeZoneWindow::updateDayNumberMaximum(int monthIndex, QSpinBox *spinBoxDay) { int maximum = 31; switch (monthIndex) { case 0: //January case 2: //March case 4: //May case 6: //July case 7: //August case 9: //October case 11: //December maximum = 31; break; case 3: //April case 5: //June case 8: //September case 10: //November maximum = 30; break; case 1: //February maximum = 29; break; default: ;// } if (spinBoxDay->value() > maximum) spinBoxDay->setValue(maximum); spinBoxDay->setRange(1, maximum); } void DefineTimeZoneWindow::updateDayNumberMaximumDstStart(int monthIndex) { updateDayNumberMaximum(monthIndex, ui->spinBoxDstStartDateDay); } void DefineTimeZoneWindow::updateDayNumberMaximumDstEnd(int monthIndex) { updateDayNumberMaximum(monthIndex, ui->spinBoxDstEndDateDay); } bool DefineTimeZoneWindow::readDstEndpoint(const QString& string, DstEndpoint endpoint) { QGroupBox* groupBox = 0; QRadioButton* radioButtonDay = 0; QRadioButton* radioButtonDate = 0; QCheckBox* checkBoxTime = 0; QComboBox* comboBoxWeek = 0; QComboBox* comboBoxMonth = 0; QComboBox* comboBoxDay = 0; QTimeEdit* timeEdit = 0; if (endpoint == DstStart) { groupBox = ui->groupBoxDstStart; radioButtonDay = ui->radioButtonDstStartDay; radioButtonDate = ui->radioButtonDstStartDate; checkBoxTime = ui->checkBoxDstStartTime; comboBoxWeek = ui->comboBoxDstStartWeek; comboBoxMonth = ui->comboBoxDstStartMonth; comboBoxDay = ui->comboBoxDstStartDay; timeEdit = ui->timeEditDstStart; } else { groupBox = ui->groupBoxDstEnd; radioButtonDay = ui->radioButtonDstEndDay; radioButtonDate = ui->radioButtonDstEndDate; checkBoxTime = ui->checkBoxDstEndTime; comboBoxWeek = ui->comboBoxDstEndWeek; comboBoxMonth = ui->comboBoxDstEndMonth; comboBoxDay = ui->comboBoxDstEndDay; timeEdit = ui->timeEditDstEnd; } QRegExp endPointFormat("(J\\d{1,3}|\\d{1,3}|M\\d{1,2}\\.\\d\\.\\d)(?:\\/(\\d{1,2}(?:\\:(?:\\d{1,2})(?:\\:(?:\\d{1,2}))?)?))?"); if (!endPointFormat.exactMatch(string)) return false; if (endPointFormat.captureCount() == 2) { QString timeString = endPointFormat.cap(2).trimmed(); if (!timeString.isEmpty()) { int hours, minutes, seconds; TimeZoneConfigurationWindow::readTzTimeString(timeString, hours, minutes, seconds); QTime time(hours, minutes, seconds); if (time.isValid()) { checkBoxTime->setChecked(true); timeEdit->setTime(time); } else return false; } } QString date = endPointFormat.cap(1); if (date.startsWith('J')) { int julianDay = date.mid(1).toInt(); if (julianDay < 1 || julianDay > 365) return false; radioButtonDate->setChecked(true); setEndPointDate(julianDay, false, endpoint); } else if (date.startsWith('M')) { QStringList list = date.mid(1).split('.'); if (list.count() != 3) return false; int month = list[0].toInt(); if (month < 1 || month > 12) return false; int week = list[1].toInt(); if (week < 1 || week > 5) return false; int day = list[2].toInt(); if (day < 0 || day > 6) return false; radioButtonDay->setChecked(true); comboBoxMonth->setCurrentIndex(month - 1); comboBoxWeek->setCurrentIndex(week - 1); comboBoxDay->setCurrentIndex(day); } else { int julianDay = date.toInt(); if (julianDay < 0 || julianDay > 365) return false; radioButtonDate->setChecked(true); setEndPointDate(julianDay+1, true, endpoint); } groupBox->setChecked(true); return true; } void DefineTimeZoneWindow::setEndPointDate(int ordinalDate, bool leapYear, DstEndpoint endpoint) { QSpinBox* spinBoxDateDay = 0; QComboBox* comboBoxDateMonth = 0; if (endpoint == DstStart) { spinBoxDateDay = ui->spinBoxDstStartDateDay; comboBoxDateMonth = ui->comboBoxDstStartDateMonth; } else { spinBoxDateDay = ui->spinBoxDstEndDateDay; comboBoxDateMonth = ui->comboBoxDstEndDateMonth; } int monthLength[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; if (leapYear) monthLength[1] = 29; for (int i = 0; i < 12; i++) { if (ordinalDate <= monthLength[i]) { spinBoxDateDay->setValue(ordinalDate); comboBoxDateMonth->setCurrentIndex(i); break; } else { ordinalDate -= monthLength[i]; } } } void DefineTimeZoneWindow::setTimeZone(QString tzString) { if (dialog == NULL) //As initialized in StelDialog return; if (tzString.isEmpty()) return; //TZ variable format: // - name // - signed offset // The following is optional: // - DST name // - DST signed offset // - DST beginning // - DST end QRegExp tzFormat("^([^:\\d,+-/]{3,})([+-]?[\\d:]+)(?:([^:\\d,+-/]{3,})((?:[+-]?[\\d:]+)?),([JM\\d\\./:]+),([JM\\d\\./:]+))?$"); if (!tzFormat.exactMatch(tzString)) return; double offset = TimeZoneConfigurationWindow::readTzOffsetString(tzFormat.cap(2)); if (fabs(offset) >= 24) return; QString name = tzFormat.cap(1).trimmed(); if (name.isEmpty()) return; ui->lineEditName->setText(name); ui->doubleSpinBoxOffset->setValue(offset); //TODO: Clean this up. The offset and the end point are not obligatory? int count = tzFormat.captureCount(); if (count > 2) { QString dstName = tzFormat.cap(3).trimmed(); if (dstName.isEmpty()) return; QString dstOffsetString = tzFormat.cap(4).trimmed(); if (!dstOffsetString.isEmpty()) { double dstOffset = TimeZoneConfigurationWindow::readTzOffsetString(dstOffsetString); if (fabs(dstOffset) >= 24) return; ui->checkBoxOffsetDst->setChecked(true); ui->doubleSpinBoxOffsetDst->setValue(dstOffset); } else { ui->checkBoxOffsetDst->setChecked(false); ui->doubleSpinBoxOffsetDst->setValue(offset + 1); } QString dstStartString = tzFormat.cap(5).trimmed(); if (!readDstEndpoint(dstStartString, DstStart)) return; QString dstEndString = tzFormat.cap(6).trimmed(); if (!readDstEndpoint(dstEndString, DstEnd)) return; ui->checkBoxDst->setChecked(true); ui->lineEditNameDst->setText(dstName); } }