/* * dtime.cpp * * Copyright (C) 1998 Luca Montecchiani * * Plasma analog-clock drawing code: * * Copyright 2007 by Aaron Seigo * Copyright 2007 by Riccardo Iaconelli * * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "dtime.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "moc_dtime.cpp" #include "helper.h" Dtime::Dtime(QWidget * parent) : QWidget(parent) { KGlobal::locale()->insertCatalog( "timezones4" ); setupUi(this); connect(setDateTimeAuto, SIGNAL(toggled(bool)), this, SLOT(serverTimeCheck())); connect(setDateTimeAuto, SIGNAL(toggled(bool)), this, SLOT(configChanged())); timeServerList->setEditable(false); connect(timeServerList, SIGNAL(activated(int)), this, SLOT(configChanged())); connect(timeServerList, SIGNAL(editTextChanged(QString)), this, SLOT(configChanged())); connect(setDateTimeAuto, SIGNAL(toggled(bool)), timeServerList, SLOT(setEnabled(bool))); timeServerList->setEnabled(false); timeServerList->setEditable(true); findNTPutility(); if (ntpUtility.isEmpty()) { setDateTimeAuto->setEnabled(false); setDateTimeAuto->setToolTip( i18n( "No NTP utility has been found. " "Install 'ntpdate' or 'rdate' command to enable automatic " "updating of date and time." ) ); } QVBoxLayout *v2 = new QVBoxLayout(timeBox); v2->setMargin(0); kclock = new Kclock(timeBox); kclock->setObjectName("Kclock"); kclock->setMinimumSize(150,150); v2->addWidget(kclock); v2->addSpacing(KDialog::spacingHint()); QHBoxLayout *v3 = new QHBoxLayout(); v2->addLayout(v3); v3->addStretch(); timeEdit = new QTimeEdit(timeBox); timeEdit->setLocale(KGlobal::locale()->toLocale()); v3->addWidget(timeEdit); v3->addStretch(); QString wtstr = i18n( "Here you can change the system time. Click into the" " hours, minutes or seconds field to change the relevant value, either" " using the up and down buttons to the right or by entering a new value." ); timeEdit->setWhatsThis(wtstr); connect(timeEdit, SIGNAL(timeChanged(QTime)), this, SLOT(set_time())); cal->setContentsMargins(2, 2, 2, 2); connect(cal, SIGNAL(activated(QDate)), this, SLOT(changeDate(QDate))); connect(cal, SIGNAL(clicked(QDate)), this, SLOT(changeDate(QDate))); connect(&internalTimer, SIGNAL(timeout()), this, SLOT(timeout())); kclock->setEnabled(false); //Timezone connect(tzonelist, SIGNAL(itemSelectionChanged()), this, SLOT(configChanged())); tzonesearch->setTreeWidget(tzonelist); } void Dtime::currentZone() { KTimeZone localZone = KSystemTimeZones::local(); if (localZone.abbreviations().isEmpty()) { m_local->setText( i18nc( "%1 is name of time zone", "Current local time zone: %1", KTimeZoneWidget::displayName(localZone) ) ); } else { m_local->setText( i18nc( "%1 is name of time zone, %2 is its abbreviation", "Current local time zone: %1 (%2)", KTimeZoneWidget::displayName(localZone), QString::fromUtf8(localZone.abbreviations().first()) ) ); } } void Dtime::serverTimeCheck() { bool enabled = !setDateTimeAuto->isChecked(); cal->setEnabled(enabled); timeEdit->setEnabled(enabled); // kclock->setEnabled(enabled); } void Dtime::findNTPutility() { static const QStringList possible_ntputilities = QStringList() << QString::fromLatin1("ntpdate") << QString::fromLatin1("rdate"); foreach(const QString &possible_ntputility, possible_ntputilities) { ntpUtility = KStandardDirs::findRootExe(possible_ntputility); if (!ntpUtility.isEmpty()) { return; } } } void Dtime::set_time() { if (ontimeout) { return; } internalTimer.stop(); time = timeEdit->time(); kclock->setTime(time); emit timeChanged(true); } void Dtime::changeDate(const QDate &d) { date = d; emit timeChanged(true); } void Dtime::configChanged() { emit timeChanged(true); } void Dtime::load() { // The config is actually written to the system config, but the user does not have any local config, // since there is nothing writing it. KConfig _config( "kcmclockrc", KConfig::NoGlobals ); KConfigGroup config(&_config, "NTP"); timeServerList->clear(); timeServerList->addItems( config.readEntry( "servers", i18n("Public Time Server (pool.ntp.org),\ asia.pool.ntp.org,\ europe.pool.ntp.org,\ north-america.pool.ntp.org,\ oceania.pool.ntp.org") ).split(',', QString::SkipEmptyParts) ); setDateTimeAuto->setChecked(config.readEntry("enabled", false)); // Reset to the current date and time time = QTime::currentTime(); date = QDate::currentDate(); cal->setSelectedDate(date); // start internal timer internalTimer.start(1000); timeout(); // Timezone currentZone(); // read the currently set time zone tzonelist->setSelected(KSystemTimeZones::local().name(), true); } void Dtime::save( QVariantMap& helperargs ) { // Save the order, but don't duplicate! QStringList list; if (timeServerList->count() != 0) { list.append(timeServerList->currentText()); } for (int i = 0; i < timeServerList->count(); i++) { QString text = timeServerList->itemText(i); if (!list.contains(text)) { list.append(text); } // Limit so errors can go away and not stored forever if (list.count() == 10) { break; } } helperargs["ntp"] = true; helperargs["ntpServers"] = list; helperargs["ntpEnabled"] = setDateTimeAuto->isChecked(); if (setDateTimeAuto->isChecked() && !ntpUtility.isEmpty()){ // NTP Time setting - done in helper timeServer = timeServerList->currentText(); kDebug() << "Setting date from time server " << timeServer; } else { // User time setting QDateTime dt(date, QTime(timeEdit->time())); kDebug() << "Set date " << dt; helperargs["date"] = true; helperargs["newdate"] = QString::number(dt.toTime_t()); helperargs["olddate"] = QString::number(::time(0)); } // restart time internalTimer.start(1000); QStringList selectedZones(tzonelist->selection()); if (selectedZones.count() > 0) { helperargs["tz"] = true; helperargs["tzone"] = selectedZones[0]; } else { helperargs["tzreset"] = true; // make the helper reset the timezone } currentZone(); } void Dtime::processHelperErrors(int code) { if (code & ClockHelper::NTPError) { KMessageBox::error(this, i18n("Unable to contact time server: %1.", timeServer)); setDateTimeAuto->setChecked(false); } if (code & ClockHelper::DateError) { KMessageBox::error(this, i18n("Can not set date.")); } if (code & ClockHelper::TimezoneError) { KMessageBox::error(this, i18n("Error setting new time zone."), i18n("Time zone Error")); } } void Dtime::timeout() { // get current time time = QTime::currentTime(); ontimeout = true; timeEdit->setTime(time); ontimeout = false; kclock->setTime(time); } QString Dtime::quickHelp() const { return i18n( "

Date & Time

This system settings module can be used to set the system date and" " time. As these settings do not only affect you as a user, but rather the whole system, you" " can only change these settings when you start the System Settings as root. If you do not have" " the root password, but feel the system time should be corrected, please contact your system" " administrator." ); } Kclock::Kclock(QWidget *parent) : QWidget(parent) { m_theme = new Plasma::Svg(this); m_theme->setImagePath("widgets/clock"); m_theme->setContainsMultipleImages(true); } Kclock::~Kclock() { delete m_theme; } void Kclock::showEvent(QShowEvent *event) { setClockSize(size()); QWidget::showEvent(event); } void Kclock::resizeEvent(QResizeEvent *event) { Q_UNUSED(event); setClockSize(size()); } void Kclock::setClockSize(const QSize &size) { int dim = qMin(size.width(), size.height()); QSize newSize = QSize(dim, dim); if (newSize != m_faceCache.size()) { m_faceCache = QPixmap(newSize); m_handsCache = QPixmap(newSize); m_glassCache = QPixmap(newSize); m_theme->resize(newSize); m_repaintCache = RepaintAll; } } void Kclock::setTime(const QTime &t) { if (t.minute() != time.minute() || t.hour() != time.hour()) { if (m_repaintCache == RepaintNone) { m_repaintCache = RepaintHands; } } time = t; update(); } void Kclock::drawHand(QPainter *p, const QRect &rect, const qreal verticalTranslation, const qreal rotation, const QString &handName) { // this code assumes the following conventions in the svg file: // - the _vertical_ position of the hands should be set with respect to the center of the face // - the _horizontal_ position of the hands does not matter // - the _shadow_ elements should have the same vertical position as their _hand_ element counterpart QRectF elementRect; QString name = handName + "HandShadow"; if (m_theme->hasElement(name)) { p->save(); elementRect = m_theme->elementRect(name); if (rect.height() < 64) { elementRect.setWidth(elementRect.width() * 2.5); } static const QPoint offset = QPoint(2, 3); p->translate(rect.x() + (rect.width() / 2) + offset.x(), rect.y() + (rect.height() / 2) + offset.y()); p->rotate(rotation); p->translate(-elementRect.width()/2, elementRect.y()-verticalTranslation); m_theme->paint(p, QRectF(QPointF(0, 0), elementRect.size()), name); p->restore(); } p->save(); name = handName + "Hand"; elementRect = m_theme->elementRect(name); if (rect.height() < 64) { elementRect.setWidth(elementRect.width() * 2.5); } p->translate(rect.x() + rect.width()/2, rect.y() + rect.height()/2); p->rotate(rotation); p->translate(-elementRect.width()/2, elementRect.y()-verticalTranslation); m_theme->paint(p, QRectF(QPointF(0, 0), elementRect.size()), name); p->restore(); } void Kclock::paintInterface(QPainter *p, const QRect &rect) { const bool m_showSecondHand = true; // compute hand angles const qreal minutes = 6.0 * time.minute() - 180; const qreal hours = 30.0 * time.hour() - 180 + ((time.minute() / 59.0) * 30.0); qreal seconds = 0; if (m_showSecondHand) { static const double anglePerSec = 6; seconds = anglePerSec * time.second() - 180; } // paint face and glass cache QRect faceRect = m_faceCache.rect(); if (m_repaintCache == RepaintAll) { m_faceCache.fill(Qt::transparent); m_glassCache.fill(Qt::transparent); QPainter facePainter(&m_faceCache); QPainter glassPainter(&m_glassCache); facePainter.setRenderHint(QPainter::SmoothPixmapTransform); glassPainter.setRenderHint(QPainter::SmoothPixmapTransform); m_theme->paint(&facePainter, m_faceCache.rect(), "ClockFace"); glassPainter.save(); QRectF elementRect = QRectF(QPointF(0, 0), m_theme->elementSize("HandCenterScrew")); glassPainter.translate(faceRect.width() / 2 - elementRect.width() / 2, faceRect.height() / 2 - elementRect.height() / 2); m_theme->paint(&glassPainter, elementRect, "HandCenterScrew"); glassPainter.restore(); m_theme->paint(&glassPainter, faceRect, "Glass"); // get vertical translation, see drawHand() for more details m_verticalTranslation = m_theme->elementRect("ClockFace").center().y(); } // paint hour and minute hands cache if (m_repaintCache == RepaintHands || m_repaintCache == RepaintAll) { m_handsCache.fill(Qt::transparent); QPainter handsPainter(&m_handsCache); handsPainter.drawPixmap(faceRect, m_faceCache, faceRect); handsPainter.setRenderHint(QPainter::SmoothPixmapTransform); drawHand(&handsPainter, faceRect, m_verticalTranslation, hours, "Hour"); drawHand(&handsPainter, faceRect, m_verticalTranslation, minutes, "Minute"); } // reset repaint cache flag m_repaintCache = RepaintNone; // paint caches and second hand QRect targetRect = faceRect; if (targetRect.width() < rect.width()) { targetRect.moveLeft((rect.width() - targetRect.width()) / 2); } p->drawPixmap(targetRect, m_handsCache, faceRect); if (m_showSecondHand) { p->setRenderHint(QPainter::SmoothPixmapTransform); drawHand(p, targetRect, m_verticalTranslation, seconds, "Second"); } p->drawPixmap(targetRect, m_glassCache, faceRect); } void Kclock::paintEvent(QPaintEvent *event) { Q_UNUSED(event); QPainter paint(this); paint.setRenderHint(QPainter::Antialiasing); paintInterface(&paint, rect()); }