File indexing completed on 2024-04-21 05:46:34
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 //--------------------------------------------------------------------------------