File: TimeDurationComboBox.qml

package info (click to toggle)
powerdevil 4%3A6.5.4-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 10,680 kB
  • sloc: cpp: 13,284; xml: 1,911; python: 1,204; sh: 19; makefile: 10
file content (150 lines) | stat: -rw-r--r-- 6,541 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/*
    SPDX-FileCopyrightText: 2024 Jakob Petsovits <jpetso@petsovits.com>

    SPDX-License-Identifier: LGPL-2.1-or-later
*/

import QtQuick
import QtQuick.Controls as QQC2

/**
 * A ComboBoxWithCustomValue for selecting durations represented by a single time unit.
 *
 * It invokes a `DurationPromptDialog` when the "Custom…" option is activated, automating the
 * conversion from option value to dialog properties and back. Time units from seconds up to weeks
 * are supported.
 */
ComboBoxWithCustomValue {
    id: root

    property string durationPromptLabel
    property string durationPromptTitle: i18nc("@title:window", "Custom Duration")

    /**
     * The list of time units accepted by the duration prompt, given as an array of
     * `DurationPromptDialog.Unit` values.
     */
    required property var durationPromptAcceptsUnits

    /**
     * The single time unit, given as `DurationPromptDialog.Unit`, that is associated to the
     * `valueRole` value of each item in the model. This unit is also used to interpret the
     * `configuredValue` property.
     *
     * For example, if `unitOfValueRole` is `DurationPromptDialog.Unit.Seconds`, then all model
     * item values will be considered as seconds and duration prompt inputs will be converted to
     * this unit accordingly.
     *
     * Generally you'll want to set this to the most fine-grained unit that the user is allowed
     * to assign/configure.
     */
    required property int unitOfValueRole

    /**
     * The time unit, given as `DurationPromptDialog.Unit`, that specifies how the
     * `configuredValue` property should be displayed to the user.
     *
     * For example, if `unitOfValueRole` is `DurationPromptDialog.Unit.Seconds` and
     * `configuredUnit` is `DurationPromptDialog.Unit.Minutes`, then the custom duration prompt
     * will display an initial value of 1 minute if the component's `configuredValue` is 60.
     */
    property int configuredDisplayUnit: durationPromptAcceptsUnits[0]

    /**
     * The lowest value that can be selected by the custom duration prompt, in units corresponding
     * to `unitOfValueRole`. The default value is 0.
     */
    property int durationPromptFromValue: 0

    /**
     * The highest value that can be selected by the custom duration prompt, in units corresponding
     * to `unitOfValueRole`. The default value is 24 hours.
     */
    property int durationPromptToValue: valueToUnit(1, DurationPromptDialog.Unit.Weeks, unitOfValueRole)

    /**
     * Will be set by this component when a custom duration prompt is confirmed.
     * If non-null, its properties include `unit` and `value`. Other than setting it, this
     * component does not make use of this property - feel free to set it back to null at any time.
     *
     * @see customDurationAccepted
     */
    property var customDuration: null

    /**
     * Emitted after the DurationPromptDialog has confirmed a custom duration value,
     * prior to calling `customValueRequestCompleted()` on the `ComboBoxWithCustomValue`
     * to finalize the request and reset the index.
     *
     * Update your setting (most likely bound to `configuredValue`) with the new `customDuration` object.
     *
     * @see customDuration
     */
    signal customDurationAccepted

    function valueToUnit(value, sourceUnit, targetUnit) {
        if (sourceUnit == targetUnit) {
            return value;
        }
        const seconds = sourceUnit === DurationPromptDialog.Unit.Seconds ? value
            : sourceUnit === DurationPromptDialog.Unit.Minutes ? (value * 60)
            : sourceUnit === DurationPromptDialog.Unit.Hours ? (value * 3600)
            : sourceUnit === DurationPromptDialog.Unit.Days ? (value * 3600 * 24)
            : sourceUnit === DurationPromptDialog.Unit.Weeks ? (value * 3600 * 24 * 7)
            : undefined;
        const result = targetUnit === DurationPromptDialog.Unit.Seconds ? seconds
            : targetUnit === DurationPromptDialog.Unit.Minutes ? (seconds / 60)
            : targetUnit === DurationPromptDialog.Unit.Hours ? (seconds / 3600)
            : targetUnit === DurationPromptDialog.Unit.Days ? (seconds / (3600 * 24))
            : targetUnit === DurationPromptDialog.Unit.Weeks ? (seconds / (3600 * 24 * 7))
            : undefined;
        if (result === undefined) {
            console.warn("Unsupported unit: TimeDurationComboBox only supports conversions between seconds, minutes, hours, days and weeks. Months and years are not supported as conversion factors are not constant.");
        }
        return result;
    }

    onCustomRequest: {
        // Pass the configured value to the dialog so it can be pre-filled in the input field.
        // Anything 0 or below is not a reasonable timeout and should be reserved for special values.
        customDurationPromptDialogLoader.sourceComponent = durationPromptDialogComponent;
        customDurationPromptDialogLoader.item.unit = configuredDisplayUnit;
        customDurationPromptDialogLoader.item.value = // `from` and `to` will clamp this value
            valueToUnit(configuredValue, unitOfValueRole, configuredDisplayUnit)
        customDurationPromptDialogLoader.item.open();
        customDurationPromptDialogLoader.item.forceActiveFocus();
    }

    /// Dialog handled by a Loader to avoid loading it until it is needed.
    Loader {
        id: customDurationPromptDialogLoader
        anchors.centerIn: parent
    }
    Component {
        id: durationPromptDialogComponent

        DurationPromptDialog {
            title: root.durationPromptTitle
            label: root.durationPromptLabel
            parent: root.QQC2.Overlay.overlay

            acceptsUnits: root.durationPromptAcceptsUnits
            from: Math.ceil(root.valueToUnit(root.durationPromptFromValue, root.unitOfValueRole, unit))
            to: Math.floor(root.valueToUnit(root.durationPromptToValue, root.unitOfValueRole, unit))

            onAccepted: {
                // Set the combo box's customUnit prior to configuredValue,
                // so the selected unit is set explicitly instead of guessed by modulo.
                root.customDuration = {value: value, unit: unit};
                root.customDurationAccepted();
                root.customRequestCompleted();
                root.forceActiveFocus();
            }
            onRejected: {
                root.customDuration = null;
                root.customRequestCompleted();
                root.forceActiveFocus();
            }
        }
    }
}