kcontrol: reimplement the datetime/clock KCM

Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
This commit is contained in:
Ivailo Monev 2024-04-05 22:52:50 +03:00
parent db8a34c067
commit d2c8392fbf
12 changed files with 388 additions and 1221 deletions

View file

@ -1,8 +1,7 @@
########### next target ###############
set(kcm_clock_PART_SRCS
dtime.cpp
main.cpp
kcm_clock.cpp
)
kde4_add_plugin(kcm_clock ${kcm_clock_PART_SRCS})
@ -18,16 +17,14 @@ install(
########### next target ###############
add_executable(kcmdatetimehelper helper.cpp)
target_link_libraries(kcmdatetimehelper KDE4::kdecore)
add_executable(kcmclockhelper kcm_clock_helper.cpp)
target_link_libraries(kcmclockhelper KDE4::kdecore)
install(
TARGETS kcmdatetimehelper
TARGETS kcmclockhelper
DESTINATION ${KDE4_LIBEXEC_INSTALL_DIR}
)
kde4_install_auth_helper_files(kcmdatetimehelper org.kde.kcontrol.kcmclock)
kde4_install_auth_helper_files(kcmclockhelper org.kde.kcontrol.kcmclock)
########### install files ###############

View file

@ -1,200 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<author>Davide Bettio &lt;davide.bettio@kdemail.net&gt;</author>
<class>DateAndTime</class>
<widget class="QWidget" name="DateAndTime">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>613</width>
<height>463</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
<string>Date and Time</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="3">
<widget class="QCheckBox" name="setDateTimeAuto">
<property name="text">
<string>Set date and time &amp;automatically:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>13</width>
<height>21</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Time server:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="buddy">
<cstring>timeServerList</cstring>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QComboBox" name="timeServerList">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="KSeparator" name="kseparator"/>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="KCalendarWidget" name="cal">
<property name="whatsThis">
<string>Here you can change the system date's day of the month, month and year.</string>
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="timeBox" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_2">
<attribute name="title">
<string>Time Zone</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>To change the local time zone, select your area from the list below.</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>5</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="m_local">
<property name="text">
<string>Current local time zone:</string>
</property>
</widget>
</item>
<item>
<widget class="KTreeWidgetSearchLine" name="tzonesearch">
<property name="enabled">
<bool>true</bool>
</property>
<property name="clickMessage">
<string>Search</string>
</property>
</widget>
</item>
<item>
<widget class="KTimeZoneWidget" name="tzonelist">
<property name="sortingEnabled">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>KTimeZoneWidget</class>
<extends>QTreeWidget</extends>
<header>ktimezonewidget.h</header>
</customwidget>
<customwidget>
<class>KTreeWidgetSearchLine</class>
<extends>KLineEdit</extends>
<header>ktreewidgetsearchline.h</header>
</customwidget>
<customwidget>
<class>KLineEdit</class>
<extends>QLineEdit</extends>
<header>klineedit.h</header>
</customwidget>
<customwidget>
<class>KSeparator</class>
<extends>QFrame</extends>
<header>kseparator.h</header>
</customwidget>
<customwidget>
<class>KCalendarWidget</class>
<extends>QCalendarWidget</extends>
<header>kcalendarwidget.h</header>
</customwidget>
</customwidgets>
<connections/>
</ui>

View file

@ -1,485 +0,0 @@
/*
* dtime.cpp
*
* Copyright (C) 1998 Luca Montecchiani <m.luca@usa.net>
*
* Plasma analog-clock drawing code:
*
* Copyright 2007 by Aaron Seigo <aseigo@kde.org>
* Copyright 2007 by Riccardo Iaconelli <riccardo@kde.org>
*
* 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 <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <sys/types.h>
#include <QComboBox>
#include <QGroupBox>
#include <QPushButton>
#include <QPainter>
#include <QDateTimeEdit>
#include <QCheckBox>
#include <QtGui/qevent.h>
#include <QGridLayout>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <kdebug.h>
#include <klocale.h>
#include <kstandarddirs.h>
#include <kmessagebox.h>
#include <kdialog.h>
#include <kconfig.h>
#include <ksystemtimezone.h>
#include <Plasma/Svg>
#include "moc_dtime.cpp"
#include "helper.h"
Dtime::Dtime(QWidget * parent)
: QWidget(parent)
{
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",
KSystemTimeZones::zoneName(localZone.name())
)
);
} else {
m_local->setText(
i18nc(
"%1 is name of time zone, %2 is its abbreviation",
"Current local time zone: %1 (%2)",
KSystemTimeZones::zoneName(localZone.name()),
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(
"<h1>Date & Time</h1> 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());
}

View file

@ -1,117 +0,0 @@
/*
* dtime.h
*
* Copyright (C) 1998 Luca Montecchiani <m.luca@usa.net>
*
* 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.
*
*/
#ifndef dtime_included
#define dtime_included
#include "ui_dateandtime.h"
#include <QSpinBox>
#include <QComboBox>
#include <QTimer>
#include <QWidget>
#include <QCheckBox>
#include <QtGui/qevent.h>
#include <QTimeEdit>
#include <knuminput.h>
class Kclock;
namespace Plasma {
class Svg;
}
class Dtime : public QWidget, public Ui::DateAndTime
{
Q_OBJECT
public:
Dtime( QWidget *parent = nullptr);
void save(QVariantMap &helperargs);
void processHelperErrors(int code);
void load();
QString quickHelp() const;
Q_SIGNALS:
void timeChanged(bool);
private Q_SLOTS:
void configChanged();
void serverTimeCheck();
void timeout();
void set_time();
void changeDate(const QDate &d);
private:
void currentZone();
void findNTPutility();
QString ntpUtility;
QTimeEdit *timeEdit;
Kclock *kclock;
QTime time;
QDate date;
QTimer internalTimer;
QString timeServer;
bool ontimeout;
};
class Kclock : public QWidget
{
Q_OBJECT
public:
Kclock(QWidget *parent = nullptr);
~Kclock();
void setTime(const QTime &t);
protected:
virtual void paintEvent(QPaintEvent *event);
virtual void showEvent(QShowEvent *event);
virtual void resizeEvent(QResizeEvent *event);
private:
void setClockSize(const QSize &size);
void drawHand(QPainter *p, const QRect &rect, const qreal verticalTranslation, const qreal rotation, const QString &handName);
void paintInterface(QPainter *p, const QRect &rect);
private:
QTime time;
Plasma::Svg *m_theme;
enum RepaintCache {
RepaintNone,
RepaintAll,
RepaintHands
};
RepaintCache m_repaintCache;
QPixmap m_faceCache;
QPixmap m_handsCache;
QPixmap m_glassCache;
qreal m_verticalTranslation;
};
#endif // dtime_included

View file

@ -1,176 +0,0 @@
/*
* tzone.cpp
*
* Copyright (C) 1998 Luca Montecchiani <m.luca@usa.net>
*
* 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.
*
*/
/*
A helper that's run using KAuth and does the system modifications.
*/
#include "helper.h"
#include <config-workspace.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
#include <stdlib.h>
#include <kcomponentdata.h>
#include <kconfig.h>
#include <kconfiggroup.h>
#include <kstandarddirs.h>
#include <ksystemtimezone.h>
#include <QProcess>
#include <QFile>
#include <QDir>
static QString findNtpUtility()
{
static const QStringList possible_ntputilities = QStringList()
<< QString::fromLatin1("ntpdate")
<< QString::fromLatin1("rdate");
foreach(const QString &possible_ntputility, possible_ntputilities) {
const QString ntpUtility = KStandardDirs::findRootExe(possible_ntputility);
if (!ntpUtility.isEmpty()) {
return ntpUtility;
}
}
return QString();
}
ClockHelper::ClockHelper(const char* const helper, QObject *parent)
: KAuthorization(helper, parent)
{
}
int ClockHelper::save(const QVariantMap &args)
{
bool _ntp = args.value("ntp").toBool();
bool _date = args.value("date").toBool();
bool _tz = args.value("tz").toBool();
bool _tzreset = args.value("tzreset").toBool();
KComponentData data("kcmdatetimehelper");
int ret = NoError; // error code
// The order here is important
if (_ntp) {
ret |= ntp(args.value("ntpServers").toStringList(), args.value("ntpEnabled").toBool());
}
if (_date) {
ret |= date(args.value("newdate").toString(), args.value("olddate").toString());
}
if (_tz) {
ret |= tz(args.value("tzone").toString());
}
if (_tzreset) {
ret |= tzreset();
}
return ret;
}
ClockHelper::CH_Error ClockHelper::ntp(const QStringList &ntpServers, bool ntpEnabled)
{
// write to the system config file
QFile config_file(KDE_CONFDIR "/kcmclockrc");
if(!config_file.exists()) {
config_file.open(QIODevice::WriteOnly);
config_file.close();
config_file.setPermissions(QFile::ReadOwner | QFile::WriteOwner | QFile::ReadGroup | QFile::ReadOther);
}
KConfig _config(config_file.fileName(), KConfig::SimpleConfig);
KConfigGroup config(&_config, "NTP");
config.writeEntry("servers", ntpServers);
config.writeEntry("enabled", ntpEnabled);
const QString ntpUtility = findNtpUtility();
if (ntpEnabled && !ntpUtility.isEmpty()) {
// NTP Time setting
QString timeServer = ntpServers.first();
if(timeServer.indexOf(QRegExp(".*\\(.*\\)$")) != -1) {
timeServer.replace(QRegExp(".*\\("), "");
timeServer.replace(QRegExp("\\).*"), "");
// Would this be better?: s/^.*\(([^)]*)\).*$/\1/
}
if (QProcess::execute(ntpUtility, QStringList() << timeServer) != 0) {
return NTPError;
}
} else if(ntpEnabled) {
return NTPError;
}
return NoError;
}
ClockHelper::CH_Error ClockHelper::date(const QString &newdate, const QString &olddate)
{
struct timeval tv;
tv.tv_sec = newdate.toULong() - olddate.toULong() + time(0);
tv.tv_usec = 0;
if (::settimeofday(&tv, 0)) {
return DateError;
}
QString hwclock = KStandardDirs::findRootExe("hwclock");
if (!hwclock.isEmpty()) {
QProcess::execute(hwclock, QStringList() << "--systohc");
}
return NoError;
}
ClockHelper::CH_Error ClockHelper::tz( const QString& selectedzone )
{
//only allow letters, numbers hyphen underscore plus and forward slash
//allowed pattern taken from time-util.c in systemd
if (!QRegExp("[a-zA-Z0-9-_+/]*").exactMatch(selectedzone)) {
return TimezoneError;
}
const QString tzdir = KSystemTimeZones::zoneinfoDir();
const QString tz = QDir::cleanPath(tzdir + QDir::separator() + selectedzone);
unlink( "/etc/localtime" );
if (!QFile::link(tz, "/etc/localtime")) {
return TimezoneError;
}
QByteArray val = ':' + tz.toAscii();
setenv("TZ", val.constData(), 1);
tzset();
return NoError;
}
ClockHelper::CH_Error ClockHelper::tzreset()
{
unlink( "/etc/localtime" );
setenv("TZ", "", 1);
tzset();
return NoError;
}
K_AUTH_MAIN("org.kde.kcontrol.kcmclock", ClockHelper)

View file

@ -1,51 +0,0 @@
/*
* main.h
*
* Copyright (C) 1998 Luca Montecchiani <m.luca@usa.net>
*
* 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.
*
*/
#ifndef CLOCK_HELPER_H
#define CLOCK_HELPER_H
#include <kauthorization.h>
class ClockHelper : public KAuthorization
{
Q_OBJECT
public:
enum CH_Error {
NoError = 0,
CallError = 1,
TimezoneError = 2,
NTPError = 4,
DateError = 8
};
ClockHelper(const char* const helper, QObject *parent = nullptr);
public slots:
int save(const QVariantMap &map);
private:
CH_Error ntp(const QStringList &ntpServers, bool ntpEnabled);
CH_Error date(const QString &newdate, const QString &olddate);
CH_Error tz(const QString &selectedzone);
CH_Error tzreset();
};
#endif // CLOCK_HELPER_H

View file

@ -0,0 +1,215 @@
/*
This file is part of the KDE project
Copyright (C) 2024 Ivailo Monev <xakepa10@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2, as published by the Free Software Foundation.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "kcm_clock.h"
#include <QThread>
#include <kaboutdata.h>
#include <kpluginfactory.h>
#include <kauthorization.h>
#include <ksystemtimezone.h>
#include <kstandarddirs.h>
#include <kmessagebox.h>
#include <kdebug.h>
static const int s_updatetime = 1000;
static const int s_waittime = 100;
static const QString s_dateformat = QString::fromLatin1("yyyy-MM-dd HH:mm:ss");
static void kWatiForTimeZone(const QString &zone)
{
while (KSystemTimeZones::local().name() != zone) {
QCoreApplication::processEvents(QEventLoop::AllEvents, s_waittime);
QThread::msleep(s_waittime);
}
}
static bool kCanChangeCLock()
{
return (!KStandardDirs::findRootExe("hwclock").isEmpty() || !KStandardDirs::findRootExe("timedatectl").isEmpty());
}
K_PLUGIN_FACTORY(KCMCLockFactory, registerPlugin<KCMCLock>();)
K_EXPORT_PLUGIN(KCMCLockFactory("kcmclock", "kcmclock"))
KCMCLock::KCMCLock(QWidget *parent, const QVariantList &args)
: KCModule(KCMCLockFactory::componentData(), parent),
m_layout(nullptr),
m_datetimebox(nullptr),
m_datetimelayout(nullptr),
m_timeedit(nullptr),
m_dateedit(nullptr),
m_timezonebox(nullptr),
m_timezonelayout(nullptr),
m_timezonewidget(nullptr),
m_timer(nullptr),
m_timechanged(false),
m_datechanged(false),
m_zonechanged(false)
{
Q_UNUSED(args);
setButtons(KCModule::Apply);
setQuickHelp(i18n("<h1>Date and Time</h1> This module allows you to change system date and time options."));
KAboutData *about = new KAboutData(
I18N_NOOP("kcmclock"), 0,
ki18n("KDE Date and Time Module"),
0, KLocalizedString(), KAboutData::License_GPL,
ki18n("Copyright 2024, Ivailo Monev <email>xakepa10@gmail.com</email>")
);
about->addAuthor(ki18n("Ivailo Monev"), KLocalizedString(), "xakepa10@gmail.com");
setAboutData(about);
m_layout = new QVBoxLayout(this);
setLayout(m_layout);
m_datetimebox = new QGroupBox(this);
m_datetimebox->setTitle(i18n("Date and time"));
m_datetimelayout = new QHBoxLayout(m_datetimebox);
m_datetimebox->setLayout(m_datetimelayout);
m_timeedit = new QTimeEdit(m_datetimebox);
// to show seconds the time format has to be in C locale
m_timeedit->setLocale(QLocale::c());
connect(m_timeedit, SIGNAL(timeChanged(QTime)), this, SLOT(slotTimeChanged()));
m_datetimelayout->addWidget(m_timeedit);
m_dateedit = new QDateEdit(m_datetimebox);
m_dateedit->setLocale(KGlobal::locale()->toLocale());
connect(m_dateedit, SIGNAL(dateChanged(QDate)), this, SLOT(slotDateChanged()));
m_datetimelayout->addWidget(m_dateedit);
m_layout->addWidget(m_datetimebox);
m_timezonebox = new QGroupBox(this);
m_timezonebox->setTitle(i18n("Time zone"));
m_timezonelayout = new QHBoxLayout(m_timezonebox);
m_timezonebox->setLayout(m_timezonelayout);
m_timezonewidget = new KTimeZoneWidget(m_timezonebox);
m_timezonewidget->setSelectionMode(QAbstractItemView::SingleSelection);
connect(m_timezonewidget, SIGNAL(itemSelectionChanged()), this, SLOT(slotZoneChanged()));
m_timezonelayout->addWidget(m_timezonewidget);
m_layout->addWidget(m_timezonebox);
m_timer = new QTimer(this);
m_timer->setInterval(s_updatetime);
connect(m_timer, SIGNAL(timeout()), this, SLOT(slotUpdate()));
if (!KAuthorization::isAuthorized("org.kde.kcontrol.kcmclock")) {
setUseRootOnlyMessage(true);
setRootOnlyMessage(i18n("You are not allowed to save the configuration"));
setDisabled(true);
} else if (!kCanChangeCLock()) {
setUseRootOnlyMessage(true);
setRootOnlyMessage(i18n("Neither 'hwclock' nor 'timedatectl' utility not found, setting the date is not possible"));
m_timeedit->setEnabled(false);
m_dateedit->setEnabled(false);
}
}
void KCMCLock::save()
{
setEnabled(false);
m_timer->stop();
m_timechanged = false;
m_datechanged = false;
m_zonechanged = false;
QVariantMap savearguments;
if (kCanChangeCLock()) {
const QDateTime datetime = QDateTime(m_dateedit->date(), m_timeedit->time());
savearguments.insert("datetime", datetime.toString(s_dateformat));
// qDebug() << Q_FUNC_INFO << datetime;
}
QString zone;
const QStringList selectedzones = m_timezonewidget->selection();
if (selectedzones.isEmpty()) {
zone = QLatin1String("UTC"); // what else?
} else {
zone = selectedzones.at(0);
}
// qDebug() << Q_FUNC_INFO << zone;
savearguments.insert("zone", zone);
const int clockreply = KAuthorization::execute(
"org.kde.kcontrol.kcmclock", "save", savearguments
);
if (clockreply > 0) {
if (clockreply == 1) {
KMessageBox::error(this, i18n("Unable to set date and time"));
kWatiForTimeZone(zone);
} else if (clockreply == 2) {
KMessageBox::error(this, i18n("Unable to set timezone"));
}
} else if (clockreply != KAuthorization::NoError) {
KMessageBox::error(this, i18n("Unable to authenticate/execute the action: %1", KAuthorization::errorString(clockreply)));
} else {
kWatiForTimeZone(zone);
}
slotUpdate();
emit changed(false);
m_timer->start();
setEnabled(true);
}
void KCMCLock::load()
{
setEnabled(false);
m_timechanged = false;
m_datechanged = false;
m_zonechanged = false;
slotUpdate();
emit changed(false);
m_timer->start();
setEnabled(true);
}
void KCMCLock::slotUpdate()
{
const QDateTime now = QDateTime::currentDateTime();
if (!m_timechanged) {
m_timeedit->blockSignals(true);
m_timeedit->setTime(now.time());
m_timeedit->blockSignals(false);
}
if (!m_datechanged) {
m_dateedit->blockSignals(true);
m_dateedit->setDate(now.date());
m_dateedit->blockSignals(false);
}
if (!m_zonechanged) {
m_timezonewidget->setSelected(KSystemTimeZones::local().name(), true);
}
}
void KCMCLock::slotTimeChanged()
{
m_timechanged = true;
emit changed(true);
}
void KCMCLock::slotDateChanged()
{
m_datechanged = true;
emit changed(true);
}
void KCMCLock::slotZoneChanged()
{
m_zonechanged = true;
emit changed(true);
}
#include "moc_kcm_clock.cpp"

View file

@ -0,0 +1,63 @@
/*
This file is part of the KDE project
Copyright (C) 2024 Ivailo Monev <xakepa10@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2, as published by the Free Software Foundation.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KCM_CLOCK_H
#define KCM_CLOCK_H
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QGroupBox>
#include <QDateTimeEdit>
#include <QTimer>
#include <kcmodule.h>
#include <ktimezonewidget.h>
class KCMCLock : public KCModule
{
Q_OBJECT
public:
KCMCLock(QWidget *parent, const QVariantList &arg);
// KCModule reimplementations
public Q_SLOTS:
void load() final;
void save() final;
private Q_SLOTS:
void slotUpdate();
void slotTimeChanged();
void slotDateChanged();
void slotZoneChanged();
private:
QVBoxLayout* m_layout;
QGroupBox* m_datetimebox;
QHBoxLayout* m_datetimelayout;
QTimeEdit* m_timeedit;
QDateEdit* m_dateedit;
QGroupBox* m_timezonebox;
QHBoxLayout* m_timezonelayout;
KTimeZoneWidget* m_timezonewidget;
QTimer* m_timer;
bool m_timechanged;
bool m_datechanged;
bool m_zonechanged;
};
#endif // main_included

View file

@ -0,0 +1,71 @@
/*
This file is part of the KDE project
Copyright (C) 2024 Ivailo Monev <xakepa10@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2, as published by the Free Software Foundation.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "kcm_clock_helper.h"
#include <QFile>
#include <QDir>
#include <QProcess>
#include <ksystemtimezone.h>
#include <kstandarddirs.h>
#include <kdebug.h>
static const QString s_localtime = QString::fromLatin1("/etc/localtime");
KCMClockHelper::KCMClockHelper(const char* const helper, QObject *parent)
: KAuthorization(helper, parent)
{
}
int KCMClockHelper::save(const QVariantMap &parameters)
{
if (!parameters.contains("zone")) {
return KAuthorization::HelperError;
}
if (parameters.contains("datetime")) {
const QString datetime = parameters.value("datetime").toString();
const QString timedatectlexe = KStandardDirs::findRootExe("timedatectl");
if (!timedatectlexe.isEmpty()) {
const QStringList timedatectlargs = QStringList()
<< "set-time" << datetime;
if (QProcess::execute(timedatectlexe, timedatectlargs) != 0) {
return 1;
}
} else {
const QString hwclockexe = KStandardDirs::findRootExe("hwclock");
const QStringList hwclockargs = QStringList()
<< "--set" << "--date" << datetime;
if (QProcess::execute(hwclockexe, hwclockargs) != 0) {
return 1;
}
}
}
const QString zone = parameters.value("zone").toString();
const QString zonefile = KSystemTimeZones::zoneinfoDir() + QDir::separator() + zone;
QFile::remove(s_localtime);
if (!QFile::link(zonefile, s_localtime)) {
return 2;
}
return KAuthorization::NoError;
}
K_AUTH_MAIN("org.kde.kcontrol.kcmclock", KCMClockHelper)

View file

@ -0,0 +1,34 @@
/*
This file is part of the KDE project
Copyright (C) 2024 Ivailo Monev <xakepa10@gmail.com>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License version 2, as published by the Free Software Foundation.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KCMCLOCKHELPER_H
#define KCMCLOCKHELPER_H
#include <kauthorization.h>
class KCMClockHelper : public KAuthorization
{
Q_OBJECT
public:
KCMClockHelper(const char* const helper, QObject *parent = nullptr);
public slots:
int save(const QVariantMap &parameters);
};
#endif // KCMCLOCKHELPER_H

View file

@ -1,137 +0,0 @@
/*
* main.cpp
*
* Copyright (C) 1998 Luca Montecchiani <m.luca@usa.net>
*
* 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 "main.h"
#include <unistd.h>
#include <QVBoxLayout>
#include <QtDBus/QtDBus>
#include <kaboutdata.h>
#include <kapplication.h>
#include <kdialog.h>
#include <kpluginfactory.h>
#include <kpluginloader.h>
#include <kmessagebox.h>
#include <kstandarddirs.h>
#include <kauthorization.h>
#include <ksystemtimezone.h>
#include "moc_main.cpp"
#include "dtime.h"
#include "helper.h"
static const int s_checktime = 1000; // 1sec
K_PLUGIN_FACTORY(KlockModuleFactory, registerPlugin<KclockModule>();)
K_EXPORT_PLUGIN(KlockModuleFactory("kcmkclock"))
KclockModule::KclockModule(QWidget *parent, const QVariantList &)
: KCModule(KlockModuleFactory::componentData(), parent)
{
KAboutData *about =
new KAboutData(
I18N_NOOP("kcmclock"), 0, ki18n("KDE Clock Control Module"),
0, KLocalizedString(), KAboutData::License_GPL,
ki18n("(c) 1996 - 2001 Luca Montecchiani\n(c) 2014 Ivailo Monev")
);
about->addAuthor(ki18n("Luca Montecchiani"), ki18n("Original author"), "m.luca@usa.net");
about->addAuthor(ki18n("Paul Campbell"), ki18n("Past Maintainer"), "paul@taniwha.com");
about->addAuthor(ki18n("Benjamin Meyer"), ki18n("Added NTP support"), "ben+kcmclock@meyerhome.net");
about->addAuthor(ki18n("Ivailo Monev"), ki18n("Current Maintainer"), "xakepa10@gmail.com");
setAboutData(about);
setQuickHelp(
i18n(
"<h1>Date & Time</h1> This control 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."
)
);
QVBoxLayout *layout = new QVBoxLayout(this);
layout->setMargin(0);
layout->setSpacing(KDialog::spacingHint());
dtime = new Dtime(this);
layout->addWidget(dtime);
connect(dtime, SIGNAL(timeChanged(bool)), this, SIGNAL(changed(bool)));
setButtons(Help|Apply);
if (!KAuthorization::isAuthorized("org.kde.kcontrol.kcmclock")) {
setUseRootOnlyMessage(true);
setRootOnlyMessage(i18n("You are not allowed to save the configuration"));
setDisabled(true);
}
m_tz = KSystemTimeZones::local().name();
QTimer::singleShot(s_checktime, this, SLOT(checkTZ()));
}
void KclockModule::save()
{
setDisabled(true);
QVariantMap helperargs;
dtime->save(helperargs);
const int reply = KAuthorization::execute(
"org.kde.kcontrol.kcmclock", "save", helperargs
);
if (reply != KAuthorization::NoError) {
if (reply < KAuthorization::NoError) {
KMessageBox::error(this, i18n("Unable to authenticate/execute the action: %1", KAuthorization::errorString(reply)));
} else {
dtime->processHelperErrors(reply);
}
setDisabled(false);
} else {
// explicit load() in case its not the timezone that is changed
load();
// not watched for
#if 0
QDBusMessage msg = QDBusMessage::createSignal("/org/kde/kcmshell_clock", "org.kde.kcmshell_clock", "clockUpdated");
QDBusConnection::sessionBus().send(msg);
#endif
}
}
void KclockModule::load()
{
dtime->load();
setDisabled(useRootOnlyMessage());
emit changed(false);
}
void KclockModule::checkTZ()
{
const QString localtz = KSystemTimeZones::local().name();
if (localtz != m_tz) {
m_tz = localtz;
load();
}
QTimer::singleShot(s_checktime, this, SLOT(checkTZ()));
}

View file

@ -1,47 +0,0 @@
/*
* main.h
*
* Copyright (C) 1998 Luca Montecchiani <m.luca@usa.net>
*
* 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.
*
*/
#ifndef main_included
#define main_included
#include <QTabWidget>
#include <kcmodule.h>
class Dtime;
class KclockModule : public KCModule
{
Q_OBJECT
public:
KclockModule(QWidget *parent, const QVariantList &);
void save();
void load();
protected Q_SLOTS:
void checkTZ();
private:
Dtime *dtime;
QString m_tz;
};
#endif // main_included