File indexing completed on 2024-04-14 15:49:44

0001 // SPDX-License-Identifier: GPL-3.0-or-later
0002 /*
0003   Copyright 2017 - 2023 Martin Koller, kollix@aon.at
0004 
0005   This file is part of liquidshell.
0006 
0007   liquidshell is free software: you can redistribute it and/or modify
0008   it under the terms of the GNU General Public License as published by
0009   the Free Software Foundation, either version 3 of the License, or
0010   (at your option) any later version.
0011 
0012   liquidshell is distributed in the hope that it will be useful,
0013   but WITHOUT ANY WARRANTY; without even the implied warranty of
0014   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0015   GNU General Public License for more details.
0016 
0017   You should have received a copy of the GNU General Public License
0018   along with liquidshell.  If not, see <http://www.gnu.org/licenses/>.
0019 */
0020 
0021 #include <ClockWidget.hxx>
0022 #include <ClockWidgetConfigureDialog.hxx>
0023 #include <DesktopWidget.hxx>
0024 
0025 #include <QVBoxLayout>
0026 #include <QHBoxLayout>
0027 #include <QDateTime>
0028 #include <QMouseEvent>
0029 #include <QApplication>
0030 #include <QScreen>
0031 #include <QPushButton>
0032 #include <QIcon>
0033 #include <QAction>
0034 #include <QTimeZone>
0035 
0036 #include <KConfig>
0037 #include <KConfigGroup>
0038 #include <KCMultiDialog>
0039 #include <KLocalizedString>
0040 #include <KPluginMetaData>
0041 #include <kcmutils_version.h>
0042 
0043 //--------------------------------------------------------------------------------
0044 
0045 CalendarPopup::CalendarPopup(QWidget *parent)
0046   : QFrame(parent)
0047 {
0048   setWindowFlags(windowFlags() | Qt::Popup);
0049   setFrameShape(QFrame::StyledPanel);
0050 
0051   QVBoxLayout *vbox = new QVBoxLayout(this);
0052   vbox->setContentsMargins(QMargins());
0053 
0054   timeLabel = new QLabel;
0055   timeLabel->setObjectName("calendar_time");
0056   QFont f = font();
0057   f.setPointSizeF(fontInfo().pointSizeF() * 1.5);
0058   timeLabel->setFont(f);
0059   timeLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
0060 
0061   dateLabel = new QLabel;
0062   dateLabel->setObjectName("calendar_date");
0063   dateLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
0064   dateLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
0065 
0066   timer.setInterval(1000);
0067   timer.start();
0068 
0069   connect(&timer, &QTimer::timeout, this, &CalendarPopup::tick);
0070 
0071   QHBoxLayout *hbox = new QHBoxLayout;
0072   hbox->setSpacing(20);
0073   hbox->addWidget(timeLabel);
0074   hbox->addWidget(dateLabel);
0075   vbox->addLayout(hbox);
0076 
0077   cal = new QCalendarWidget;
0078   vbox->addWidget(cal);
0079 
0080   QPushButton *today = new QPushButton(QIcon::fromTheme("go-jump-today"), QString());
0081   vbox->addWidget(today);
0082   connect(today, &QPushButton::clicked, this, &CalendarPopup::goToday);
0083 }
0084 
0085 //--------------------------------------------------------------------------------
0086 
0087 void CalendarPopup::showEvent(QShowEvent *event)
0088 {
0089   Q_UNUSED(event);
0090 
0091   timer.start();
0092   tick();
0093 }
0094 
0095 //--------------------------------------------------------------------------------
0096 
0097 void CalendarPopup::hideEvent(QHideEvent *event)
0098 {
0099   Q_UNUSED(event);
0100 
0101   timer.stop();  // avoid timer events we don't need
0102 }
0103 
0104 //--------------------------------------------------------------------------------
0105 
0106 void CalendarPopup::tick()
0107 {
0108   // show time and date in localized long form
0109   QDateTime dateTime = QDateTime::currentDateTime();
0110   timeLabel->setText(locale().toString(dateTime.time()));
0111   dateLabel->setText(locale().toString(dateTime.date()));
0112 }
0113 
0114 //--------------------------------------------------------------------------------
0115 
0116 void CalendarPopup::goToday()
0117 {
0118   cal->showToday();
0119   cal->setSelectedDate(QDate::currentDate());
0120 }
0121 
0122 //--------------------------------------------------------------------------------
0123 //--------------------------------------------------------------------------------
0124 //--------------------------------------------------------------------------------
0125 
0126 ClockWidget::ClockWidget(DesktopPanel *parent)
0127   : QFrame(parent), calendar(nullptr)
0128 {
0129   timeFormat = locale().timeFormat(QLocale::ShortFormat);
0130 
0131   ensurePolished();  // make sure we already have the css applied
0132 
0133   timer = new QTimer(this);
0134 
0135   // if seconds are shown, update every second, else less often
0136   if ( timeFormat.contains('s') )
0137     timer->setInterval(1000);
0138   else
0139     timer->setInterval(5000);
0140 
0141   timer->start();
0142   connect(timer, &QTimer::timeout, this, &ClockWidget::tick);
0143 
0144   connect(parent, &DesktopPanel::rowsChanged, this, &ClockWidget::fill);
0145 
0146   timeLabel = new QLabel(this);
0147   dayLabel = new QLabel(this);
0148   dateLabel = new QLabel(this);
0149 
0150   timeLabel->setObjectName("time");
0151   dayLabel->setObjectName("day");
0152   dateLabel->setObjectName("date");
0153 
0154   timeLabel->setTextFormat(Qt::PlainText);
0155   dayLabel->setTextFormat(Qt::PlainText);
0156   dateLabel->setTextFormat(Qt::PlainText);
0157 
0158   timeLabel->setAlignment(Qt::AlignCenter);
0159   dayLabel->setAlignment(Qt::AlignCenter);
0160   dateLabel->setAlignment(Qt::AlignCenter);
0161 
0162   QFont f = font();
0163   f.setPointSizeF(fontInfo().pointSizeF() * 1.5);
0164   f.setBold(true);
0165   timeLabel->setFont(f);
0166 
0167   fill();
0168 
0169   timeLabel->setVisible(!timeFormat.isEmpty());
0170   dayLabel->setVisible(!dayFormat.isEmpty());
0171   dateLabel->setVisible(!dateFormat.isEmpty());
0172 
0173   // context menu
0174   QAction *action = new QAction(this);
0175   action->setIcon(QIcon::fromTheme("configure"));
0176   action->setText(i18n("Select Timezones..."));
0177   addAction(action);
0178   connect(action, &QAction::triggered,
0179           [this]()
0180           {
0181             ClockWidgetConfigureDialog dialog(parentWidget(), timeZoneIds);
0182             dialog.setWindowTitle(i18n("Select Timezones"));
0183             dialog.resize(600, 400);
0184             if ( dialog.exec() == QDialog::Accepted )
0185             {
0186               timeZoneIds = dialog.getSelectedTimeZoneIds();
0187               KConfig config;
0188               KConfigGroup group = config.group("ClockWidget");
0189               QStringList list;
0190               for (const QByteArray &id : timeZoneIds)
0191                 list.append(id);
0192               group.writeEntry("timeZoneIds", list);
0193               tick();  // update tooltip
0194             }
0195           }
0196          );
0197 
0198   action = new QAction(this);
0199   action->setIcon(QIcon::fromTheme("preferences-system-time"));
0200   action->setText(i18n("Configure Date & Time..."));
0201   addAction(action);
0202   connect(action, &QAction::triggered,
0203           [this]()
0204           {
0205             auto dialog = new KCMultiDialog(parentWidget());
0206             dialog->setAttribute(Qt::WA_DeleteOnClose);
0207             dialog->setWindowTitle(i18n("Date & Time"));
0208 
0209 #if KCMUTILS_VERSION >= QT_VERSION_CHECK(5, 85, 0)
0210             KPluginMetaData data("plasma/kcms/systemsettings_qwidgets/kcm_clock");
0211             if ( data.isValid() )
0212               dialog->addModule(data);
0213 #else
0214             {
0215               KCModuleInfo module("kcm_clock");
0216               if ( module.service() )
0217                 dialog->addModule(module);
0218               else
0219                 dialog->addModule("clock");  // in older KDE versions
0220             }
0221 #endif
0222             dialog->adjustSize();
0223             dialog->show();
0224           }
0225          );
0226   setContextMenuPolicy(Qt::ActionsContextMenu);
0227 
0228   // load config
0229   KConfig config;
0230   KConfigGroup group = config.group("ClockWidget");
0231   QStringList list;
0232   list = group.readEntry<QStringList>("timeZoneIds", QStringList());
0233   for (const QString &id : list)
0234     timeZoneIds.append(id.toLatin1());
0235 
0236   tick();
0237 
0238   timeLabel->setFixedHeight(timeLabel->fontMetrics().tightBoundingRect(timeLabel->text()).height() + 2);
0239   dayLabel->setFixedHeight(dayLabel->fontMetrics().tightBoundingRect(dayLabel->text()).height() + 4);
0240   dateLabel->setFixedHeight(dateLabel->fontMetrics().tightBoundingRect(dateLabel->text()).height() + 4);
0241 }
0242 
0243 //--------------------------------------------------------------------------------
0244 
0245 void ClockWidget::fill()
0246 {
0247   delete layout();
0248 
0249   const int MAX_ROWS = qobject_cast<DesktopPanel *>(parentWidget())->getRows();
0250 
0251   QBoxLayout *box;
0252   if ( MAX_ROWS >= 2 )
0253   {
0254     box = new QVBoxLayout(this);
0255     box->setSpacing(0);
0256   }
0257   else
0258   {
0259     box = new QHBoxLayout(this);
0260   }
0261 
0262   box->setContentsMargins(QMargins());
0263 
0264   box->addWidget(timeLabel);
0265   box->addWidget(dayLabel);
0266   box->addWidget(dateLabel);
0267 }
0268 
0269 //--------------------------------------------------------------------------------
0270 
0271 void ClockWidget::tick()
0272 {
0273   QDateTime dateTimeUtc = QDateTime::currentDateTimeUtc();
0274   QDateTime dateTime = dateTimeUtc.toLocalTime();
0275 
0276   timeLabel->setText(dateTime.time().toString(timeFormat));
0277   dayLabel->setText(dateTime.date().toString(dayFormat));
0278   dateLabel->setText(dateTime.date().toString(dateFormat));
0279 
0280   if ( !timeZoneIds.isEmpty() )
0281   {
0282     QString tip = "<html><table cellpadding=5 style='white-space:pre;'>";
0283     for (const QByteArray &id : timeZoneIds)
0284     {
0285       QTimeZone timeZone(id);
0286       QDateTime dt = dateTimeUtc;
0287       dateTime = dt.toTimeZone(timeZone);
0288 
0289       tip += QString("<tr><td>%1</td> <td>%2</td> <td>%3</td> <td>%4</td></tr>")
0290                      .arg(QLatin1String(id))
0291                      .arg(dateTime.time().toString(timeFormat))
0292                      .arg(dateTime.date().toString(dayFormat))
0293                      .arg(dateTime.date().toString(dateFormat));
0294     }
0295     tip += "</table></html>";
0296     setToolTip(tip);
0297   }
0298 }
0299 
0300 //--------------------------------------------------------------------------------
0301 
0302 void ClockWidget::mousePressEvent(QMouseEvent *event)
0303 {
0304   if ( event->button() == Qt::LeftButton )
0305   {
0306     if ( !calendar )
0307       calendar = new CalendarPopup(this);
0308 
0309     calendar->goToday();
0310     QPoint point = mapToGlobal(pos());
0311     QRect screen = DesktopWidget::availableGeometry();
0312     point.setX(std::min(point.x(), screen.x() + screen.width() - calendar->sizeHint().width()));
0313     point.setY(point.y() - calendar->sizeHint().height());
0314     calendar->move(point);
0315     calendar->show();
0316   }
0317 }
0318 
0319 //--------------------------------------------------------------------------------