Warning, /plasma/plasma-workspace/applets/digital-clock/package/contents/ui/DigitalClock.qml is written in an unsupported language. File is not indexed.

0001 /*
0002     SPDX-FileCopyrightText: 2013 Heena Mahour <heena393@gmail.com>
0003     SPDX-FileCopyrightText: 2013 Sebastian Kügler <sebas@kde.org>
0004     SPDX-FileCopyrightText: 2013 Martin Klapetek <mklapetek@kde.org>
0005     SPDX-FileCopyrightText: 2014 David Edmundson <davidedmundson@kde.org>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 
0010 import QtQuick
0011 import QtQuick.Layouts 1.1
0012 import QtQuick.Window 2.2
0013 import org.kde.plasma.plasmoid 2.0
0014 import org.kde.plasma.core as PlasmaCore
0015 import org.kde.plasma.components 3.0 as Components
0016 import org.kde.plasma.private.digitalclock 1.0
0017 import org.kde.kirigami 2.20 as Kirigami
0018 
0019 MouseArea {
0020     id: main
0021     objectName: "digital-clock-compactrepresentation"
0022 
0023     property string timeFormat
0024     property string timeFormatWithSeconds
0025 
0026     property bool showLocalTimezone: Plasmoid.configuration.showLocalTimezone
0027     property bool showDate: Plasmoid.configuration.showDate
0028     property bool localizeDate: Plasmoid.configuration.dateFormat === "longDate" || Plasmoid.configuration.dateFormat === "shortDate"
0029     property var dateFormat: {
0030         if (Plasmoid.configuration.dateFormat === "custom") {
0031             return Plasmoid.configuration.customDateFormat; // str
0032         } else if (Plasmoid.configuration.dateFormat === "longDate") {
0033             return Locale.LongFormat; // int
0034         } else if (Plasmoid.configuration.dateFormat === "isoDate") {
0035             return Qt.ISODate; // int
0036         } else { // "shortDate"
0037             return Locale.ShortFormat; // int
0038         }
0039     }
0040 
0041     property string lastSelectedTimezone: Plasmoid.configuration.lastSelectedTimezone
0042     property int displayTimezoneFormat: Plasmoid.configuration.displayTimezoneFormat
0043     property int use24hFormat: Plasmoid.configuration.use24hFormat
0044 
0045     property string lastDate: ""
0046     property int tzOffset
0047 
0048     // This is the index in the list of user selected timezones
0049     property int tzIndex: 0
0050 
0051     // if showing the date and the time in one line or
0052     // if the date/timezone cannot be fit with the smallest font to its designated space
0053     property bool oneLineMode: {
0054         if (Plasmoid.configuration.dateDisplayFormat === 1) {
0055             // BesideTime
0056             return true;
0057         } else if (Plasmoid.configuration.dateDisplayFormat === 2) {
0058             // BelowTime
0059             return false;
0060         } else {
0061             // Adaptive
0062             return Plasmoid.formFactor === PlasmaCore.Types.Horizontal &&
0063                 main.height <= 2 * Kirigami.Theme.smallFont.pixelSize &&
0064                 (main.showDate || timezoneLabel.visible);
0065         }
0066     }
0067 
0068     property bool wasExpanded
0069     property int wheelDelta: 0
0070 
0071     Accessible.role: Accessible.Button
0072     Accessible.onPressAction: main.clicked(null)
0073 
0074     onDateFormatChanged: {
0075         setupLabels();
0076     }
0077 
0078     onDisplayTimezoneFormatChanged: { setupLabels(); }
0079     onStateChanged: { setupLabels(); }
0080 
0081     onLastSelectedTimezoneChanged: { timeFormatCorrection(Qt.locale().timeFormat(Locale.ShortFormat)) }
0082     onShowLocalTimezoneChanged:    { timeFormatCorrection(Qt.locale().timeFormat(Locale.ShortFormat)) }
0083     onShowDateChanged:             { timeFormatCorrection(Qt.locale().timeFormat(Locale.ShortFormat)) }
0084     onUse24hFormatChanged:         { timeFormatCorrection(Qt.locale().timeFormat(Locale.ShortFormat)) }
0085 
0086     Connections {
0087         target: Plasmoid
0088         function onContextualActionsAboutToShow() {
0089             ClipboardMenu.secondsIncluded = (Plasmoid.configuration.showSeconds === 2);
0090             ClipboardMenu.currentDate = main.getCurrentTime();
0091         }
0092     }
0093 
0094     Connections {
0095         target: Plasmoid.configuration
0096         function onSelectedTimeZonesChanged() {
0097             // If the currently selected timezone was removed,
0098             // default to the first one in the list
0099             const lastSelectedTimezone = Plasmoid.configuration.lastSelectedTimezone;
0100             if (Plasmoid.configuration.selectedTimeZones.indexOf(lastSelectedTimezone) === -1) {
0101                 Plasmoid.configuration.lastSelectedTimezone = Plasmoid.configuration.selectedTimeZones[0];
0102             }
0103 
0104             setupLabels();
0105             setTimezoneIndex();
0106         }
0107     }
0108 
0109     function getCurrentTime() {
0110         // get the time for the given timezone from the dataengine
0111         var now = dataSource.data[Plasmoid.configuration.lastSelectedTimezone]["DateTime"];
0112         // get current UTC time
0113         var msUTC = now.getTime() + (now.getTimezoneOffset() * 60000);
0114         // add the dataengine TZ offset to it
0115         var currentTime = new Date(msUTC + (dataSource.data[Plasmoid.configuration.lastSelectedTimezone]["Offset"] * 1000));
0116         return currentTime;
0117     }
0118 
0119     function pointToPixel(pointSize) {
0120         var pixelsPerInch = Screen.pixelDensity * 25.4
0121         return Math.round(pointSize / 72 * pixelsPerInch)
0122     }
0123 
0124     states: [
0125         State {
0126             name: "horizontalPanel"
0127             when: Plasmoid.formFactor === PlasmaCore.Types.Horizontal && !main.oneLineMode
0128 
0129             PropertyChanges {
0130                 target: main
0131                 Layout.fillHeight: true
0132                 Layout.fillWidth: false
0133                 Layout.minimumWidth: contentItem.width
0134                 Layout.maximumWidth: Layout.minimumWidth
0135             }
0136 
0137             PropertyChanges {
0138                 target: contentItem
0139 
0140                 height: timeLabel.height + (main.showDate || timezoneLabel.visible ? 0.8 * timeLabel.height : 0)
0141                 width: Math.max(timeLabel.width + (main.showDate ? timezoneLabel.paintedWidth : 0),
0142                                 timezoneLabel.paintedWidth, dateLabel.paintedWidth) + Kirigami.Units.largeSpacing
0143             }
0144 
0145             PropertyChanges {
0146                 target: labelsGrid
0147 
0148                 rows: main.showDate ? 1 : 2
0149             }
0150 
0151             AnchorChanges {
0152                 target: labelsGrid
0153 
0154                 anchors.horizontalCenter: contentItem.horizontalCenter
0155             }
0156 
0157             PropertyChanges {
0158                 target: timeLabel
0159 
0160                 height: sizehelper.height
0161                 width: timeLabel.paintedWidth
0162 
0163                 font.pixelSize: timeLabel.height
0164             }
0165 
0166             PropertyChanges {
0167                 target: timezoneLabel
0168 
0169                 height: main.showDate ? 0.7 * timeLabel.height : 0.8 * timeLabel.height
0170                 width: main.showDate ? timezoneLabel.paintedWidth : timeLabel.width
0171 
0172                 font.pixelSize: timezoneLabel.height
0173             }
0174 
0175             PropertyChanges {
0176                 target: dateLabel
0177 
0178                 height: 0.8 * timeLabel.height
0179                 width: dateLabel.paintedWidth
0180                 verticalAlignment: Text.AlignVCenter
0181 
0182                 font.pixelSize: dateLabel.height
0183             }
0184 
0185             AnchorChanges {
0186                 target: dateLabel
0187 
0188                 anchors.top: labelsGrid.bottom
0189                 anchors.horizontalCenter: labelsGrid.horizontalCenter
0190             }
0191 
0192             PropertyChanges {
0193                 target: sizehelper
0194 
0195                 /*
0196                  * The value 0.71 was picked by testing to give the clock the right
0197                  * size (aligned with tray icons).
0198                  * Value 0.56 seems to be chosen rather arbitrary as well such that
0199                  * the time label is slightly larger than the date or timezone label
0200                  * and still fits well into the panel with all the applied margins.
0201                  */
0202                 height: Math.min(main.showDate || timezoneLabel.visible ? main.height * 0.56 : main.height * 0.71,
0203                                  fontHelper.font.pixelSize)
0204 
0205                 font.pixelSize: sizehelper.height
0206             }
0207         },
0208 
0209         State {
0210             name: "oneLineDate"
0211             // the one-line mode has no effect on a vertical panel because it would never fit
0212             when: Plasmoid.formFactor !== PlasmaCore.Types.Vertical && main.oneLineMode
0213 
0214             PropertyChanges {
0215                 target: main
0216                 Layout.fillHeight: true
0217                 Layout.fillWidth: false
0218                 Layout.minimumWidth: contentItem.width
0219                 Layout.maximumWidth: Layout.minimumWidth
0220 
0221             }
0222 
0223             PropertyChanges {
0224                 target: contentItem
0225 
0226                 height: sizehelper.height
0227                 width: dateLabel.width + dateLabel.anchors.rightMargin + labelsGrid.width
0228             }
0229 
0230             AnchorChanges {
0231                 target: labelsGrid
0232 
0233                 anchors.right: contentItem.right
0234             }
0235 
0236             PropertyChanges {
0237                 target: dateLabel
0238 
0239                 height: timeLabel.height
0240                 width: dateLabel.paintedWidth
0241 
0242                 font.pixelSize: 1024
0243                 verticalAlignment: Text.AlignVCenter
0244                 anchors.rightMargin: labelsGrid.columnSpacing
0245 
0246                 fontSizeMode: Text.VerticalFit
0247             }
0248 
0249             AnchorChanges {
0250                 target: dateLabel
0251 
0252                 anchors.right: labelsGrid.left
0253                 anchors.verticalCenter: labelsGrid.verticalCenter
0254             }
0255 
0256             PropertyChanges {
0257                 target: timeLabel
0258 
0259                 height: sizehelper.height
0260                 width: timeLabel.paintedWidth
0261 
0262                 fontSizeMode: Text.VerticalFit
0263             }
0264 
0265             PropertyChanges {
0266                 target: timezoneLabel
0267 
0268                 height: 0.7 * timeLabel.height
0269                 width: timezoneLabel.paintedWidth
0270 
0271                 fontSizeMode: Text.VerticalFit
0272                 horizontalAlignment: Text.AlignHCenter
0273             }
0274 
0275             PropertyChanges {
0276                 target: sizehelper
0277 
0278                 height: Math.min(main.height, fontHelper.contentHeight)
0279 
0280                 fontSizeMode: Text.VerticalFit
0281                 font.pixelSize: fontHelper.font.pixelSize
0282             }
0283         },
0284 
0285         State {
0286             name: "verticalPanel"
0287             when: Plasmoid.formFactor === PlasmaCore.Types.Vertical
0288 
0289             PropertyChanges {
0290                 target: main
0291                 Layout.fillHeight: false
0292                 Layout.fillWidth: true
0293                 Layout.maximumHeight: contentItem.height
0294                 Layout.minimumHeight: Layout.maximumHeight
0295             }
0296 
0297             PropertyChanges {
0298                 target: contentItem
0299 
0300                 height: main.showDate ? labelsGrid.height + dateLabel.contentHeight : labelsGrid.height
0301                 width: main.width
0302             }
0303 
0304             PropertyChanges {
0305                 target: labelsGrid
0306 
0307                 rows: 2
0308             }
0309 
0310             PropertyChanges {
0311                 target: timeLabel
0312 
0313                 height: sizehelper.contentHeight
0314                 width: main.width
0315 
0316                 font.pixelSize: Math.min(timeLabel.height, fontHelper.font.pixelSize)
0317                 fontSizeMode: Text.VerticalFit
0318             }
0319 
0320             PropertyChanges {
0321                 target: timezoneLabel
0322 
0323                 height: Math.max(0.7 * timeLabel.height, minimumPixelSize)
0324                 width: main.width
0325 
0326                 fontSizeMode: Text.Fit
0327                 minimumPixelSize: dateLabel.minimumPixelSize
0328                 elide: Text.ElideRight
0329             }
0330 
0331             PropertyChanges {
0332                 target: dateLabel
0333 
0334                 width: main.width
0335                 //NOTE: in order for Text.Fit to work as intended, the actual height needs to be quite big, in order for the font to enlarge as much it needs for the available width, and then request a sensible height, for which contentHeight will need to be considered as opposed to height
0336                 height: Kirigami.Units.gridUnit * 10
0337 
0338                 fontSizeMode: Text.Fit
0339                 verticalAlignment: Text.AlignTop
0340                 // Those magic numbers are purely what looks nice as maximum size, here we have it the smallest
0341                 // between slightly bigger than the default font (1.4 times) and a bit smaller than the time font
0342                 font.pixelSize: Math.min(0.7 * timeLabel.height, Kirigami.Theme.defaultFont.pixelSize * 1.4)
0343                 elide: Text.ElideRight
0344                 wrapMode: Text.WordWrap
0345             }
0346 
0347             AnchorChanges {
0348                 target: dateLabel
0349 
0350                 anchors.top: labelsGrid.bottom
0351                 anchors.horizontalCenter: labelsGrid.horizontalCenter
0352             }
0353 
0354             PropertyChanges {
0355                 target: sizehelper
0356 
0357                 width: main.width
0358 
0359                 fontSizeMode: Text.HorizontalFit
0360                 font.pixelSize: fontHelper.font.pixelSize
0361             }
0362         },
0363 
0364         State {
0365             name: "other"
0366             when: Plasmoid.formFactor !== PlasmaCore.Types.Vertical && Plasmoid.formFactor !== PlasmaCore.Types.Horizontal
0367 
0368             PropertyChanges {
0369                 target: main
0370                 Layout.fillHeight: false
0371                 Layout.fillWidth: false
0372                 Layout.minimumWidth: Kirigami.Units.gridUnit * 3
0373                 Layout.minimumHeight: Kirigami.Units.gridUnit * 3
0374             }
0375 
0376             PropertyChanges {
0377                 target: contentItem
0378 
0379                 height: main.height
0380                 width: main.width
0381             }
0382 
0383             PropertyChanges {
0384                 target: labelsGrid
0385 
0386                 rows: 2
0387             }
0388 
0389             PropertyChanges {
0390                 target: timeLabel
0391 
0392                 height: sizehelper.height
0393                 width: main.width
0394 
0395                 fontSizeMode: Text.Fit
0396             }
0397 
0398             PropertyChanges {
0399                 target: timezoneLabel
0400 
0401                 height: 0.7 * timeLabel.height
0402                 width: main.width
0403 
0404                 fontSizeMode: Text.Fit
0405                 minimumPixelSize: 1
0406             }
0407 
0408             PropertyChanges {
0409                 target: dateLabel
0410 
0411                 height: 0.7 * timeLabel.height
0412                 font.pixelSize: 1024
0413                 width: Math.max(timeLabel.contentWidth, Kirigami.Units.gridUnit * 3)
0414                 verticalAlignment: Text.AlignVCenter
0415 
0416                 fontSizeMode: Text.Fit
0417                 minimumPixelSize: 1
0418                 wrapMode: Text.WordWrap
0419             }
0420 
0421             AnchorChanges {
0422                 target: dateLabel
0423 
0424                 anchors.top: labelsGrid.bottom
0425                 anchors.horizontalCenter: labelsGrid.horizontalCenter
0426             }
0427 
0428             PropertyChanges {
0429                 target: sizehelper
0430 
0431                 height: {
0432                     if (main.showDate) {
0433                         if (timezoneLabel.visible) {
0434                             return 0.4 * main.height
0435                         }
0436                         return 0.56 * main.height
0437                     } else if (timezoneLabel.visible) {
0438                         return 0.59 * main.height
0439                     }
0440                     return main.height
0441                 }
0442                 width: main.width
0443 
0444                 fontSizeMode: Text.Fit
0445                 font.pixelSize: 1024
0446             }
0447         }
0448     ]
0449 
0450     onPressed: wasExpanded = root.expanded
0451     onClicked: root.expanded = !wasExpanded
0452     onWheel: wheel => {
0453         if (!Plasmoid.configuration.wheelChangesTimezone) {
0454             return;
0455         }
0456 
0457         var delta = (wheel.inverted ? -1 : 1) * (wheel.angleDelta.y ? wheel.angleDelta.y : wheel.angleDelta.x);
0458         var newIndex = main.tzIndex;
0459         wheelDelta += delta;
0460         // magic number 120 for common "one click"
0461         // See: https://doc.qt.io/qt-5/qml-qtquick-wheelevent.html#angleDelta-prop
0462         while (wheelDelta >= 120) {
0463             wheelDelta -= 120;
0464             newIndex--;
0465         }
0466         while (wheelDelta <= -120) {
0467             wheelDelta += 120;
0468             newIndex++;
0469         }
0470 
0471         if (newIndex >= Plasmoid.configuration.selectedTimeZones.length) {
0472             newIndex = 0;
0473         } else if (newIndex < 0) {
0474             newIndex = Plasmoid.configuration.selectedTimeZones.length - 1;
0475         }
0476 
0477         if (newIndex !== main.tzIndex) {
0478             Plasmoid.configuration.lastSelectedTimezone = Plasmoid.configuration.selectedTimeZones[newIndex];
0479             main.tzIndex = newIndex;
0480 
0481             dataSource.dataChanged();
0482             setupLabels();
0483         }
0484     }
0485 
0486    /*
0487     * Visible elements
0488     *
0489     */
0490     Item {
0491         id: contentItem
0492         anchors.verticalCenter: main.verticalCenter
0493 
0494         Grid {
0495             id: labelsGrid
0496 
0497             rows: 1
0498             horizontalItemAlignment: Grid.AlignHCenter
0499             verticalItemAlignment: Grid.AlignVCenter
0500 
0501             flow: Grid.TopToBottom
0502             columnSpacing: Kirigami.Units.smallSpacing
0503 
0504             Components.Label  {
0505                 id: timeLabel
0506 
0507                 font {
0508                     family: fontHelper.font.family
0509                     weight: fontHelper.font.weight
0510                     italic: fontHelper.font.italic
0511                     pixelSize: 1024
0512                     pointSize: -1 // Because we're setting the pixel size instead
0513                                   // TODO: remove once this label is ported to PC3
0514                 }
0515                 minimumPixelSize: 1
0516 
0517                 text: Qt.formatTime(main.getCurrentTime(), Plasmoid.configuration.showSeconds === 2 ? main.timeFormatWithSeconds : main.timeFormat)
0518                 textFormat: Text.PlainText
0519 
0520                 verticalAlignment: Text.AlignVCenter
0521                 horizontalAlignment: Text.AlignHCenter
0522             }
0523 
0524             Components.Label {
0525                 id: timezoneLabel
0526 
0527                 font.weight: timeLabel.font.weight
0528                 font.italic: timeLabel.font.italic
0529                 font.pixelSize: 1024
0530                 font.pointSize: -1 // Because we're setting the pixel size instead
0531                                    // TODO: remove once this label is ported to PC3
0532                 minimumPixelSize: 1
0533 
0534                 visible: text.length > 0
0535                 horizontalAlignment: Text.AlignHCenter
0536                 verticalAlignment: Text.AlignVCenter
0537                 textFormat: Text.PlainText
0538             }
0539         }
0540 
0541         Components.Label {
0542             id: dateLabel
0543 
0544             visible: main.showDate
0545 
0546             font.family: timeLabel.font.family
0547             font.weight: timeLabel.font.weight
0548             font.italic: timeLabel.font.italic
0549             font.pixelSize: 1024
0550             font.pointSize: -1 // Because we're setting the pixel size instead
0551                                // TODO: remove once this label is ported to PC3
0552             minimumPixelSize: 1
0553 
0554             horizontalAlignment: Text.AlignHCenter
0555             verticalAlignment: Text.AlignVCenter
0556             textFormat: Text.PlainText
0557         }
0558     }
0559     /*
0560      * end: Visible Elements
0561      *
0562      */
0563 
0564     Components.Label {
0565         id: sizehelper
0566 
0567         font.family: timeLabel.font.family
0568         font.weight: timeLabel.font.weight
0569         font.italic: timeLabel.font.italic
0570         minimumPixelSize: 1
0571 
0572         visible: false
0573         textFormat: Text.PlainText
0574     }
0575 
0576     // To measure Label.height for maximum-sized font in VerticalFit mode
0577     Components.Label {
0578         id: fontHelper
0579 
0580         height: 1024
0581 
0582         font.family: (Plasmoid.configuration.autoFontAndSize || Plasmoid.configuration.fontFamily.length === 0) ? Kirigami.Theme.defaultFont.family : Plasmoid.configuration.fontFamily
0583         font.weight: Plasmoid.configuration.autoFontAndSize ? Kirigami.Theme.defaultFont.weight : Plasmoid.configuration.fontWeight
0584         font.italic: Plasmoid.configuration.autoFontAndSize ? Kirigami.Theme.defaultFont.italic : Plasmoid.configuration.italicText
0585         font.pixelSize: Plasmoid.configuration.autoFontAndSize ? 3 * Kirigami.Theme.defaultFont.pixelSize : pointToPixel(Plasmoid.configuration.fontSize)
0586         font.pointSize: -1
0587         fontSizeMode: Text.VerticalFit
0588 
0589         visible: false
0590         textFormat: Text.PlainText
0591     }
0592 
0593     FontMetrics {
0594         id: timeMetrics
0595 
0596         font.family: timeLabel.font.family
0597         font.weight: timeLabel.font.weight
0598         font.italic: timeLabel.font.italic
0599     }
0600 
0601     // Qt's QLocale does not offer any modular time creating like Klocale did
0602     // eg. no "gimme time with seconds" or "gimme time without seconds and with timezone".
0603     // QLocale supports only two formats - Long and Short. Long is unusable in many situations
0604     // and Short does not provide seconds. So if seconds are enabled, we need to add it here.
0605     //
0606     // What happens here is that it looks for the delimiter between "h" and "m", takes it
0607     // and appends it after "mm" and then appends "ss" for the seconds.
0608     function timeFormatCorrection(timeFormatString) {
0609         const regexp = /(hh*)(.+)(mm)/i
0610         const match = regexp.exec(timeFormatString);
0611 
0612         const hours = match[1];
0613         const delimiter = match[2];
0614         const minutes = match[3]
0615         const seconds = "ss";
0616         const amPm = "AP";
0617         const uses24hFormatByDefault = timeFormatString.toLowerCase().indexOf("ap") === -1;
0618 
0619         // because QLocale is incredibly stupid and does not convert 12h/24h clock format
0620         // when uppercase H is used for hours, needs to be h or hh, so toLowerCase()
0621         let result = hours.toLowerCase() + delimiter + minutes;
0622 
0623         let result_sec = result + delimiter + seconds;
0624 
0625         // add "AM/PM" either if the setting is the default and locale uses it OR if the user unchecked "use 24h format"
0626         if ((main.use24hFormat == Qt.PartiallyChecked && !uses24hFormatByDefault) || main.use24hFormat == Qt.Unchecked) {
0627             result += " " + amPm;
0628             result_sec += " " + amPm;
0629         }
0630 
0631         main.timeFormat = result;
0632         main.timeFormatWithSeconds = result_sec;
0633         setupLabels();
0634     }
0635 
0636     function setupLabels() {
0637         const showTimezone = main.showLocalTimezone || (Plasmoid.configuration.lastSelectedTimezone !== "Local"
0638                                                         && dataSource.data["Local"]["Timezone City"] !== dataSource.data[Plasmoid.configuration.lastSelectedTimezone]["Timezone City"]);
0639 
0640         let timezoneString = "";
0641 
0642         if (showTimezone) {
0643             // format timezone as tz code, city or UTC offset
0644             if (displayTimezoneFormat === 0) {
0645                 timezoneString = dataSource.data[lastSelectedTimezone]["Timezone Abbreviation"]
0646             } else if (displayTimezoneFormat === 1) {
0647                 timezoneString = TimezonesI18n.i18nCity(dataSource.data[lastSelectedTimezone]["Timezone"]);
0648             } else if (displayTimezoneFormat === 2) {
0649                 const lastOffset = dataSource.data[lastSelectedTimezone]["Offset"];
0650                 const symbol = lastOffset > 0 ? '+' : '';
0651                 const hours = Math.floor(lastOffset / 3600);
0652                 const minutes = Math.floor(lastOffset % 3600 / 60);
0653 
0654                 timezoneString = "UTC" + symbol + hours.toString().padStart(2, '0') + ":" + minutes.toString().padStart(2, '0');
0655             }
0656 
0657             timezoneLabel.text = (main.showDate || main.oneLineMode) && Plasmoid.formFactor === PlasmaCore.Types.Horizontal ? "(" + timezoneString + ")" : timezoneString;
0658         } else {
0659             // this clears the label and that makes it hidden
0660             timezoneLabel.text = timezoneString;
0661         }
0662 
0663         if (main.showDate) {
0664             if (main.localizeDate) {
0665                 dateLabel.text = Qt.formatDate(main.getCurrentTime(), Qt.locale(), main.dateFormat);
0666             } else {
0667                 dateLabel.text = Qt.formatDate(main.getCurrentTime(), main.dateFormat);
0668             }
0669         } else {
0670             // clear it so it doesn't take space in the layout
0671             dateLabel.text = "";
0672         }
0673 
0674         // find widest character between 0 and 9
0675         let maximumWidthNumber = 0;
0676         let maximumAdvanceWidth = 0;
0677         for (let i = 0; i <= 9; i++) {
0678             const advanceWidth = timeMetrics.advanceWidth(i);
0679             if (advanceWidth > maximumAdvanceWidth) {
0680                 maximumAdvanceWidth = advanceWidth;
0681                 maximumWidthNumber = i;
0682             }
0683         }
0684         // replace all placeholders with the widest number (two digits)
0685         const format = main.timeFormat.replace(/(h+|m+|s+)/g, "" + maximumWidthNumber + maximumWidthNumber); // make sure maximumWidthNumber is formatted as string
0686         // build the time string twice, once with an AM time and once with a PM time
0687         const date = new Date(2000, 0, 1, 1, 0, 0);
0688         const timeAm = Qt.formatTime(date, format);
0689         const advanceWidthAm = timeMetrics.advanceWidth(timeAm);
0690         date.setHours(13);
0691         const timePm = Qt.formatTime(date, format);
0692         const advanceWidthPm = timeMetrics.advanceWidth(timePm);
0693         // set the sizehelper's text to the widest time string
0694         if (advanceWidthAm > advanceWidthPm) {
0695             sizehelper.text = timeAm;
0696         } else {
0697             sizehelper.text = timePm;
0698         }
0699         fontHelper.text = sizehelper.text
0700     }
0701 
0702     function dateTimeChanged() {
0703         let doCorrections = false;
0704 
0705         if (main.showDate) {
0706             // If the date has changed, force size recalculation, because the day name
0707             // or the month name can now be longer/shorter, so we need to adjust applet size
0708             const currentDate = Qt.formatDateTime(main.getCurrentTime(), "yyyy-MM-dd");
0709             if (main.lastDate !== currentDate) {
0710                 doCorrections = true;
0711                 main.lastDate = currentDate
0712             }
0713         }
0714 
0715         const currentTZOffset = dataSource.data["Local"]["Offset"] / 60;
0716         if (currentTZOffset !== tzOffset) {
0717             doCorrections = true;
0718             tzOffset = currentTZOffset;
0719             Date.timeZoneUpdated(); // inform the QML JS engine about TZ change
0720         }
0721 
0722         if (doCorrections) {
0723             timeFormatCorrection(Qt.locale().timeFormat(Locale.ShortFormat));
0724         }
0725     }
0726 
0727     function setTimezoneIndex() {
0728         main.tzIndex = Plasmoid.configuration.selectedTimeZones.indexOf(Plasmoid.configuration.lastSelectedTimezone);
0729     }
0730 
0731     Component.onCompleted: {
0732         // Sort the timezones according to their offset
0733         // Calling sort() directly on Plasmoid.configuration.selectedTimeZones
0734         // has no effect, so sort a copy and then assign the copy to it
0735         const sortedTimeZones = Plasmoid.configuration.selectedTimeZones;
0736         const byOffset = (a, b) => dataSource.data[a]["Offset"] - dataSource.data[b]["Offset"];
0737         sortedTimeZones.sort(byOffset);
0738         Plasmoid.configuration.selectedTimeZones = sortedTimeZones;
0739 
0740         setTimezoneIndex();
0741         tzOffset = -(new Date().getTimezoneOffset());
0742         dateTimeChanged();
0743         timeFormatCorrection(Qt.locale().timeFormat(Locale.ShortFormat));
0744         dataSource.onDataChanged.connect(dateTimeChanged);
0745     }
0746 }