on 239fdcc help sign in
unity8/qml/Panel/Indicators/MenuItemFactory.qml
1022 lines 38 kB history raw
1/*
2 * Copyright 2013,2015 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
17import QtQuick 2.4
18import QtQuick.Window 2.2
19import Ubuntu.Settings.Menus 0.1 as Menus
20import Ubuntu.Settings.Components 0.1
21import QMenuModel 0.1
22import Utils 0.1 as Utils
23import Ubuntu.Components.ListItems 1.3 as ListItems
24import Ubuntu.Components 1.3
25import Unity.Session 0.1
26import Unity.Platform 1.0
28Item {
29 id: menuFactory
31 property var rootModel: null
32 property var menuModel: null
34 property var _map: {
35 "default": {
36 "unity.widgets.systemsettings.tablet.volumecontrol" : sliderMenu,
37 "unity.widgets.systemsettings.tablet.switch" : switchMenu,
39 "com.canonical.indicator.button" : buttonMenu,
40 "com.canonical.indicator.div" : separatorMenu,
41 "com.canonical.indicator.section" : sectionMenu,
42 "com.canonical.indicator.progress" : progressMenu,
43 "com.canonical.indicator.slider" : sliderMenu,
44 "com.canonical.indicator.switch" : switchMenu,
45 "com.canonical.indicator.alarm" : alarmMenu,
46 "com.canonical.indicator.appointment" : appointmentMenu,
47 "com.canonical.indicator.transfer" : transferMenu,
48 "com.canonical.indicator.button-section" : buttonSectionMenu,
49 "com.canonical.indicator.link" : linkMenu,
51 "com.canonical.indicator.messages.messageitem" : messageItem,
52 "com.canonical.indicator.messages.sourceitem" : groupedMessage,
54 "com.canonical.unity.slider" : sliderMenu,
55 "com.canonical.unity.switch" : switchMenu,
57 "com.canonical.unity.media-player" : mediaPayerMenu,
58 "com.canonical.unity.playback-item" : playbackItemMenu,
60 "unity.widgets.systemsettings.tablet.wifisection" : wifiSection,
61 "unity.widgets.systemsettings.tablet.accesspoint" : accessPoint,
62 "com.canonical.indicator.network.modeminfoitem" : modeminfoitem,
64 "com.canonical.indicator.calendar": calendarMenu,
65 "com.canonical.indicator.location": timezoneMenu,
66 },
67 "indicator-session": {
68 "indicator.user-menu-item": Platform.isPC ? userMenuItem : null,
69 "indicator.guest-menu-item": Platform.isPC ? userMenuItem : null,
70 "com.canonical.indicator.switch": Math.min(Screen.width, Screen.height) > units.gu(60) ? switchMenu : null // Desktop mode switch
71 },
72 "indicator-messages" : {
73 "com.canonical.indicator.button" : messagesButtonMenu
74 }
75 }
77 function getExtendedProperty(object, propertyName, defaultValue) {
78 if (object && object.hasOwnProperty(propertyName)) {
79 return object[propertyName];
80 }
81 return defaultValue;
82 }
84 Component {
85 id: separatorMenu;
87 Menus.SeparatorMenu {
88 objectName: "separatorMenu"
89 }
90 }
92 Component {
93 id: sliderMenu;
95 Menus.SliderMenu {
96 id: sliderItem
97 objectName: "sliderMenu"
98 property QtObject menuData: null
99 property var menuModel: menuFactory.menuModel
100 property int menuIndex: -1
101 property var extendedData: menuData && menuData.ext || undefined
102 property var serverValue: getExtendedProperty(menuData, "actionState", undefined)
104 text: menuData && menuData.label || ""
105 iconSource: menuData && menuData.icon || ""
106 minIcon: getExtendedProperty(extendedData, "minIcon", "")
107 maxIcon: getExtendedProperty(extendedData, "maxIcon", "")
109 minimumValue: getExtendedProperty(extendedData, "minValue", 0.0)
110 maximumValue: {
111 var maximum = getExtendedProperty(extendedData, "maxValue", 1.0);
112 if (maximum <= minimumValue) {
113 return minimumValue + 1;
114 }
115 return maximum;
116 }
117 enabled: menuData && menuData.sensitive || false
118 highlightWhenPressed: false
120 onMenuModelChanged: {
121 loadAttributes();
122 }
123 onMenuIndexChanged: {
124 loadAttributes();
125 }
127 function loadAttributes() {
128 if (!menuModel || menuIndex == -1) return;
129 menuModel.loadExtendedAttributes(menuIndex, {'min-value': 'double',
130 'max-value': 'double',
131 'min-icon': 'icon',
132 'max-icon': 'icon',
133 'x-canonical-sync-action': 'string'});
134 }
136 ServerPropertySynchroniser {
137 id: sliderPropertySync
138 objectName: "sync"
139 syncTimeout: Utils.Constants.indicatorValueTimeout
140 bufferedSyncTimeout: true
141 maximumWaitBufferInterval: 16
143 serverTarget: sliderItem
144 serverProperty: "serverValue"
145 userTarget: sliderItem
146 userProperty: "value"
148 onSyncTriggered: menuModel.changeState(menuIndex, value)
149 }
151 UnityMenuAction {
152 model: menuModel
153 index: menuIndex
154 name: getExtendedProperty(extendedData, "xCanonicalSyncAction", "")
155 onStateChanged: {
156 sliderPropertySync.reset();
157 sliderPropertySync.updateUserValue();
158 }
159 }
160 }
161 }
163 Component {
164 id: buttonMenu;
166 Menus.ButtonMenu {
167 objectName: "buttonMenu"
168 property QtObject menuData: null
169 property var menuModel: menuFactory.menuModel
170 property int menuIndex: -1
172 buttonText: menuData && menuData.label || ""
173 enabled: menuData && menuData.sensitive || false
174 highlightWhenPressed: false
176 onTriggered: {
177 menuModel.activate(menuIndex);
178 }
179 }
180 }
182 Component {
183 id: messagesButtonMenu;
185 Item {
186 objectName: "messagesButtonMenu"
187 property QtObject menuData: null
188 property var menuModel: menuFactory.menuModel
189 property int menuIndex: -1
191 implicitHeight: units.gu(5)
192 enabled: menuData && menuData.sensitive || false
194 Label {
195 id: buttonMenuLabel
196 text: menuData && menuData.label || ""
197 anchors.centerIn: parent
198 font.bold: true
199 }
201 MouseArea {
202 anchors {
203 fill: buttonMenuLabel
204 margins: units.gu(-1)
205 }
206 onClicked: menuModel.activate(menuIndex);
207 }
208 }
209 }
211 Component {
212 id: sectionMenu;
214 Menus.SectionMenu {
215 objectName: "sectionMenu"
216 property QtObject menuData: null
217 property var menuIndex: undefined
219 text: menuData && menuData.label || ""
220 busy: false
221 }
222 }
224 Component {
225 id: progressMenu;
227 Menus.ProgressValueMenu {
228 objectName: "progressMenu"
229 property QtObject menuData: null
230 property int menuIndex: -1
232 text: menuData && menuData.label || ""
233 iconSource: menuData && menuData.icon || ""
234 value : menuData && menuData.actionState || 0.0
235 enabled: menuData && menuData.sensitive || false
236 // FIXME: Because of this bug, setting it to the theme foreground color (white)
237 // currently doesn't work. Let's hack it to be "close enough"
238 // https://bugs.launchpad.net/ubuntu/+source/ubuntu-ui-toolkit/+bug/1555784
239 foregroundColor: "#fffffe"
240 highlightWhenPressed: false
241 }
242 }
244 Component {
245 id: standardMenu;
247 Menus.StandardMenu {
248 objectName: "standardMenu"
249 property QtObject menuData: null
250 property int menuIndex: -1
252 text: menuData && menuData.label || ""
253 iconSource: menuData && menuData.icon || ""
254 enabled: menuData && menuData.sensitive || false
255 highlightWhenPressed: false
257 onTriggered: {
258 menuModel.activate(menuIndex);
259 }
261 // FIXME : At the moment, the indicators aren't using
262 // com.canonical.indicators.link for settings menu. Need to fudge it.
263 property bool settingsMenu: menuData && menuData.action.indexOf("settings") > -1 || false
264 backColor: settingsMenu ? Qt.rgba(1,1,1,0.07) : "transparent"
265 component: settingsMenu ? buttonForSettings : undefined
266 Component {
267 id: buttonForSettings
268 Icon {
269 name: "settings"
270 height: units.gu(3)
271 width: height
272 color: theme.palette.normal.backgroundText
273 }
274 }
275 }
276 }
278 Component {
279 id: linkMenu;
281 Menus.StandardMenu {
282 objectName: "linkMenu"
283 property QtObject menuData: null
284 property int menuIndex: -1
286 text: menuData && menuData.label || ""
287 iconSource: menuData && menuData.icon || ""
288 enabled: menuData && menuData.sensitive || false
289 highlightWhenPressed: false
291 onTriggered: {
292 menuModel.activate(menuIndex);
293 }
295 backColor: Qt.rgba(1,1,1,0.07)
297 component: menuData.icon ? icon : undefined
298 Component {
299 id: icon
300 Icon {
301 source: menuData.icon
302 height: units.gu(3)
303 width: height
304 color: theme.palette.normal.backgroundText
305 }
306 }
307 }
308 }
310 Component {
311 id: checkableMenu;
313 Menus.CheckableMenu {
314 id: checkItem
315 objectName: "checkableMenu"
316 property QtObject menuData: null
317 property int menuIndex: -1
318 property bool serverChecked: menuData && menuData.isToggled || false
320 text: menuData && menuData.label || ""
321 enabled: menuData && menuData.sensitive || false
322 checked: serverChecked
323 highlightWhenPressed: false
325 ServerPropertySynchroniser {
326 objectName: "sync"
327 syncTimeout: Utils.Constants.indicatorValueTimeout
329 serverTarget: checkItem
330 serverProperty: "serverChecked"
331 userTarget: checkItem
332 userProperty: "checked"
334 onSyncTriggered: menuModel.activate(checkItem.menuIndex)
335 }
336 }
337 }
339 Component {
340 id: switchMenu;
342 Menus.SwitchMenu {
343 id: switchItem
344 objectName: "switchMenu"
345 property QtObject menuData: null
346 property int menuIndex: -1
347 property bool serverChecked: menuData && menuData.isToggled || false
349 text: menuData && menuData.label || ""
350 iconSource: menuData && menuData.icon || ""
351 enabled: menuData && menuData.sensitive || false
352 checked: serverChecked
353 highlightWhenPressed: false
355 ServerPropertySynchroniser {
356 objectName: "sync"
357 syncTimeout: Utils.Constants.indicatorValueTimeout
359 serverTarget: switchItem
360 serverProperty: "serverChecked"
361 userTarget: switchItem
362 userProperty: "checked"
364 onSyncTriggered: menuModel.activate(switchItem.menuIndex);
365 }
366 }
367 }
369 Component {
370 id: alarmMenu;
372 Menus.EventMenu {
373 id: alarmItem
374 objectName: "alarmMenu"
375 property QtObject menuData: null
376 property var menuModel: menuFactory.menuModel
377 property int menuIndex: -1
378 property var extendedData: menuData && menuData.ext || undefined
380 property date serverTime: new Date(getExtendedProperty(extendedData, "xCanonicalTime", 0) * 1000)
381 LiveTimer {
382 frequency: LiveTimer.Relative
383 relativeTime: alarmItem.serverTime
384 onTrigger: alarmItem.serverTime = new Date(getExtendedProperty(extendedData, "xCanonicalTime", 0) * 1000)
385 }
387 text: menuData && menuData.label || ""
388 iconSource: menuData && menuData.icon || "image://theme/alarm-clock"
389 time: i18n.relativeDateTime(serverTime)
390 enabled: menuData && menuData.sensitive || false
391 highlightWhenPressed: false
393 onMenuModelChanged: {
394 loadAttributes();
395 }
396 onMenuIndexChanged: {
397 loadAttributes();
398 }
399 onTriggered: {
400 menuModel.activate(menuIndex);
401 }
403 function loadAttributes() {
404 if (!menuModel || menuIndex == -1) return;
405 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-time': 'int64'});
406 }
407 }
408 }
410 Component {
411 id: appointmentMenu;
413 Menus.EventMenu {
414 id: appointmentItem
415 objectName: "appointmentMenu"
416 property QtObject menuData: null
417 property var menuModel: menuFactory.menuModel
418 property int menuIndex: -1
419 property var extendedData: menuData && menuData.ext || undefined
421 readonly property date serverTime: new Date(getExtendedProperty(extendedData, "xCanonicalTime", 0) * 1000)
423 LiveTimer {
424 frequency: LiveTimer.Relative
425 relativeTime: appointmentItem.serverTime
426 onTrigger: appointmentItem.time = i18n.relativeDateTime(appointmentItem.serverTime)
427 }
429 text: menuData && menuData.label || ""
430 iconSource: menuData && menuData.icon || "image://theme/calendar"
431 time: i18n.relativeDateTime(serverTime)
432 eventColor: getExtendedProperty(extendedData, "xCanonicalColor", Qt.rgba(0.0, 0.0, 0.0, 0.0))
433 enabled: menuData && menuData.sensitive || false
434 highlightWhenPressed: false
436 onMenuModelChanged: {
437 loadAttributes();
438 }
439 onMenuIndexChanged: {
440 loadAttributes();
441 }
442 onTriggered: {
443 menuModel.activate(menuIndex);
444 }
446 function loadAttributes() {
447 if (!menuModel || menuIndex == -1) return;
448 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-color': 'string',
449 'x-canonical-time': 'int64'});
450 }
451 }
452 }
454 Component {
455 id: userMenuItem
457 Menus.UserSessionMenu {
458 objectName: "userSessionMenu"
459 highlightWhenPressed: false
461 property QtObject menuData: null
462 property var menuModel: menuFactory.menuModel
463 property int menuIndex: -1
465 name: menuData && menuData.label || "" // label is the user's real name
466 iconSource: menuData && menuData.icon || ""
468 // would be better to compare with the logname but sadly the indicator doesn't expose that
469 active: DBusUnitySessionService.RealName() !== "" ? DBusUnitySessionService.RealName() == name
470 : DBusUnitySessionService.UserName() == name
472 onTriggered: {
473 menuModel.activate(menuIndex);
474 }
475 }
476 }
478 Component {
479 id: calendarMenu
481 Menus.CalendarMenu {
482 objectName: "calendarMenu"
483 highlightWhenPressed: false
484 focus: true
485 }
486 }
488 Component {
489 id: timezoneMenu
491 Menus.TimeZoneMenu {
492 id: tzMenuItem
493 objectName: "timezoneMenu"
495 property QtObject menuData: null
496 property var menuModel: menuFactory.menuModel
497 property int menuIndex: -1
498 property var extendedData: menuData && menuData.ext || undefined
499 readonly property string tz: getExtendedProperty(extendedData, "xCanonicalTimezone", "UTC")
500 property var updateTimer: Timer {
501 repeat: true
502 running: tzMenuItem.visible // only run when we're open
503 onTriggered: tzMenuItem.time = Utils.TimezoneFormatter.currentTimeInTimezone(tzMenuItem.tz)
504 }
506 city: menuData && menuData.label || ""
507 time: Utils.TimezoneFormatter.currentTimeInTimezone(tz)
508 enabled: menuData && menuData.sensitive || false
510 onMenuModelChanged: {
511 loadAttributes();
512 }
513 onMenuIndexChanged: {
514 loadAttributes();
515 }
516 onTriggered: {
517 tzActionGroup.setLocation.activate(tz);
518 }
520 QDBusActionGroup {
521 id: tzActionGroup
522 busType: DBus.SessionBus
523 busName: "com.canonical.indicator.datetime"
524 objectPath: "/com/canonical/indicator/datetime"
526 property variant setLocation: action("set-location")
528 Component.onCompleted: tzActionGroup.start()
529 }
531 function loadAttributes() {
532 if (!menuModel || menuIndex == -1) return;
533 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-timezone': 'string'});
534 }
535 }
536 }
538 Component {
539 id: wifiSection;
541 Menus.SectionMenu {
542 objectName: "wifiSection"
543 property QtObject menuData: null
544 property var menuModel: menuFactory.menuModel
545 property int menuIndex: -1
546 property var extendedData: menuData && menuData.ext || undefined
548 text: menuData && menuData.label || ""
549 busy: getExtendedProperty(extendedData, "xCanonicalBusyAction", false)
551 onMenuModelChanged: {
552 loadAttributes();
553 }
554 onMenuIndexChanged: {
555 loadAttributes();
556 }
558 function loadAttributes() {
559 if (!menuModel || menuIndex == -1) return;
560 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-busy-action': 'bool'})
561 }
562 }
563 }
565 Component {
566 id: accessPoint;
568 Menus.AccessPointMenu {
569 id: apItem
570 objectName: "accessPoint"
571 property QtObject menuData: null
572 property var menuModel: menuFactory.menuModel
573 property int menuIndex: -1
574 property var extendedData: menuData && menuData.ext || undefined
575 property bool serverChecked: menuData && menuData.isToggled || false
577 property var strengthAction: UnityMenuAction {
578 model: menuModel
579 index: menuIndex
580 name: getExtendedProperty(extendedData, "xCanonicalWifiApStrengthAction", "")
581 }
583 text: menuData && menuData.label || ""
584 enabled: menuData && menuData.sensitive || false
585 active: serverChecked
586 secure: getExtendedProperty(extendedData, "xCanonicalWifiApIsSecure", false)
587 adHoc: getExtendedProperty(extendedData, "xCanonicalWifiApIsAdhoc", false)
588 signalStrength: {
589 if (strengthAction.valid) {
590 var state = strengthAction.state; // handle both int and uchar
591 // FIXME remove the special casing when we switch to indicator-network completely
592 if (typeof state == "string") {
593 return state.charCodeAt();
594 }
595 return state;
596 }
597 return 0;
598 }
599 highlightWhenPressed: false
601 onMenuModelChanged: {
602 loadAttributes();
603 }
604 onMenuIndexChanged: {
605 loadAttributes();
606 }
608 function loadAttributes() {
609 if (!menuModel || menuIndex == -1) return;
610 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-wifi-ap-is-adhoc': 'bool',
611 'x-canonical-wifi-ap-is-secure': 'bool',
612 'x-canonical-wifi-ap-strength-action': 'string'});
613 }
615 ServerPropertySynchroniser {
616 objectName: "sync"
617 syncTimeout: Utils.Constants.indicatorValueTimeout
619 serverTarget: apItem
620 serverProperty: "serverChecked"
621 userTarget: apItem
622 userProperty: "active"
623 userTrigger: "onTriggered"
625 onSyncTriggered: menuModel.activate(apItem.menuIndex)
626 }
627 }
628 }
630 Component {
631 id: modeminfoitem;
632 Menus.ModemInfoItem {
633 objectName: "modemInfoItem"
634 property QtObject menuData: null
635 property var menuModel: menuFactory.menuModel
636 property int menuIndex: -1
637 property var extendedData: menuData && menuData.ext || undefined
638 highlightWhenPressed: false
640 property var statusLabelAction: UnityMenuAction {
641 model: menuModel
642 index: menuIndex
643 name: getExtendedProperty(extendedData, "xCanonicalModemStatusLabelAction", "")
644 }
645 statusText: statusLabelAction.valid ? statusLabelAction.state : ""
647 property var statusIconAction: UnityMenuAction {
648 model: menuModel
649 index: menuIndex
650 name: getExtendedProperty(extendedData, "xCanonicalModemStatusIconAction", "")
651 }
652 statusIcon: statusIconAction.valid ? statusIconAction.state : ""
654 property var connectivityIconAction: UnityMenuAction {
655 model: menuModel
656 index: menuIndex
657 name: getExtendedProperty(extendedData, "xCanonicalModemConnectivityIconAction", "")
658 }
659 connectivityIcon: connectivityIconAction.valid ? connectivityIconAction.state : ""
661 property var simIdentifierLabelAction: UnityMenuAction {
662 model: menuModel
663 index: menuIndex
664 name: getExtendedProperty(extendedData, "xCanonicalModemSimIdentifierLabelAction", "")
665 }
666 simIdentifierText: simIdentifierLabelAction.valid ? simIdentifierLabelAction.state : ""
668 property var roamingAction: UnityMenuAction {
669 model: menuModel
670 index: menuIndex
671 name: getExtendedProperty(extendedData, "xCanonicalModemRoamingAction", "")
672 }
673 roaming: roamingAction.valid ? roamingAction.state : false
675 property var unlockAction: UnityMenuAction {
676 model: menuModel
677 index: menuIndex
678 name: getExtendedProperty(extendedData, "xCanonicalModemLockedAction", "")
679 }
680 onUnlock: {
681 unlockAction.activate();
682 }
683 locked: unlockAction.valid ? unlockAction.state : false
685 onMenuModelChanged: {
686 loadAttributes();
687 }
688 onMenuIndexChanged: {
689 loadAttributes();
690 }
692 function loadAttributes() {
693 if (!menuModel || menuIndex == -1) return;
694 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-modem-status-label-action': 'string',
695 'x-canonical-modem-status-icon-action': 'string',
696 'x-canonical-modem-connectivity-icon-action': 'string',
697 'x-canonical-modem-sim-identifier-label-action': 'string',
698 'x-canonical-modem-roaming-action': 'string',
699 'x-canonical-modem-locked-action': 'string'});
700 }
701 }
702 }
704 Component {
705 id: messageItem
707 MessageMenuItemFactory {
708 objectName: "messageItem"
709 menuModel: menuFactory.menuModel
710 }
711 }
713 Component {
714 id: groupedMessage
716 Menus.GroupedMessageMenu {
717 objectName: "groupedMessage"
718 property QtObject menuData: null
719 property var menuModel: menuFactory.menuModel
720 property int menuIndex: -1
721 property var extendedData: menuData && menuData.ext || undefined
723 text: menuData && menuData.label || ""
724 iconSource: getExtendedProperty(extendedData, "icon", "image://theme/message")
725 count: menuData && menuData.actionState.length > 0 ? menuData.actionState[0] : "0"
726 enabled: menuData && menuData.sensitive || false
727 highlightWhenPressed: false
728 removable: true
730 onMenuModelChanged: {
731 loadAttributes();
732 }
733 onMenuIndexChanged: {
734 loadAttributes();
735 }
736 onClicked: {
737 menuModel.activate(menuIndex, true);
738 }
739 onDismissed: {
740 menuModel.activate(menuIndex, false);
741 }
743 function loadAttributes() {
744 if (!menuModel || menuIndex == -1) return;
745 menuModel.loadExtendedAttributes(modelIndex, {'icon': 'icon'});
746 }
747 }
748 }
750 Component {
751 id: mediaPayerMenu;
753 Menus.MediaPlayerMenu {
754 objectName: "mediaPayerMenu"
755 property QtObject menuData: null
756 property var menuModel: menuFactory.menuModel
757 property int menuIndex: -1
758 property var actionState: menuData && menuData.actionState || undefined
759 property bool running: getExtendedProperty(actionState, "running", false)
761 playerIcon: menuData && menuData.icon || "image://theme/stock_music"
762 playerName: menuData && menuData.label || i18n.tr("Nothing is playing")
764 albumArt: getExtendedProperty(actionState, "art-url", "image://theme/stock_music")
765 song: getExtendedProperty(actionState, "title", "")
766 artist: getExtendedProperty(actionState, "artist", "")
767 album: getExtendedProperty(actionState, "album", "")
768 showTrack: running && (state == "Playing" || state == "Paused")
769 state: getExtendedProperty(actionState, "state", "")
770 enabled: menuData && menuData.sensitive || false
771 highlightWhenPressed: false
772 showDivider: false
774 onTriggered: {
775 model.activate(modelIndex);
776 }
777 }
778 }
780 Component {
781 id: playbackItemMenu;
783 Menus.PlaybackItemMenu {
784 objectName: "playbackItemMenu"
785 property QtObject menuData: null
786 property var menuModel: menuFactory.menuModel
787 property int menuIndex: -1
788 property var extendedData: menuData && menuData.ext || undefined
790 property var playAction: UnityMenuAction {
791 model: menuModel
792 index: menuIndex
793 name: getExtendedProperty(extendedData, "xCanonicalPlayAction", "")
794 }
795 property var nextAction: UnityMenuAction {
796 model: menuModel
797 index: menuIndex
798 name: getExtendedProperty(extendedData, "xCanonicalNextAction", "")
799 }
800 property var previousAction: UnityMenuAction {
801 model: menuModel
802 index: menuIndex
803 name: getExtendedProperty(extendedData, "xCanonicalPreviousAction", "")
804 }
806 playing: playAction.state === "Playing"
807 canPlay: playAction.valid
808 canGoNext: nextAction.valid
809 canGoPrevious: previousAction.valid
810 enabled: menuData && menuData.sensitive || false
811 highlightWhenPressed: false
813 onPlay: {
814 playAction.activate();
815 }
816 onNext: {
817 nextAction.activate();
818 }
819 onPrevious: {
820 previousAction.activate();
821 }
822 onMenuModelChanged: {
823 loadAttributes();
824 }
825 onMenuIndexChanged: {
826 loadAttributes();
827 }
829 function loadAttributes() {
830 if (!menuModel || menuIndex == -1) return;
831 menuModel.loadExtendedAttributes(modelIndex, {'x-canonical-play-action': 'string',
832 'x-canonical-next-action': 'string',
833 'x-canonical-previous-action': 'string'});
834 }
835 }
836 }
838 Component {
839 id: transferMenu
841 Menus.TransferMenu {
842 objectName: "transferMenu"
843 id: transfer
844 property QtObject menuData: null
845 property var menuModel: menuFactory.menuModel
846 property int menuIndex: -1
847 property var extendedData: menuData && menuData.ext || undefined
848 property var uid: getExtendedProperty(extendedData, "xCanonicalUid", undefined)
850 text: menuData && menuData.label || ""
851 iconSource: menuData && menuData.icon || "image://theme/transfer-none"
852 maximum: 1.0
853 enabled: menuData && menuData.sensitive || false
854 highlightWhenPressed: false
855 removable: true
856 confirmRemoval: true
858 QDBusActionGroup {
859 id: actionGroup
860 busType: 1
861 busName: rootModel.busName
862 objectPath: rootModel.actions["indicator"]
864 property var activateAction: action("activate-transfer")
865 property var cancelAction: action("cancel-transfer")
866 property var transferStateAction: uid !== undefined ? action("transfer-state."+uid) : null
868 Component.onCompleted: actionGroup.start()
869 }
871 property var transferState: {
872 if (actionGroup.transferStateAction === null) return undefined;
873 return actionGroup.transferStateAction.valid ? actionGroup.transferStateAction.state : undefined
874 }
876 property var runningState : transferState !== undefined ? transferState["state"] : undefined
877 property var secondsLeft : transferState !== undefined ? transferState["seconds-left"] : undefined
879 active: runningState !== undefined && runningState !== Menus.TransferState.Finished
880 progress: transferState !== undefined ? transferState["percent"] : 0.0
882 // TODO - Should be in the SDK
883 property var timeRemaining: {
884 if (secondsLeft === undefined) return undefined;
886 var remaining = "";
887 var hours = Math.floor(secondsLeft / (60 * 60));
888 var minutes = Math.floor(secondsLeft / 60) % 60;
889 var seconds = secondsLeft % 60;
890 if (hours > 0) {
891 remaining += i18n.tr("%1 hour", "%1 hours", hours).arg(hours)
892 }
893 if (minutes > 0) {
894 if (remaining != "") remaining += ", ";
895 remaining += i18n.tr("%1 minute", "%1 minutes", minutes).arg(minutes)
896 }
897 // don't include seconds if hours > 0
898 if (hours == 0 && minutes < 5 && seconds > 0) {
899 if (remaining != "") remaining += ", ";
900 remaining += i18n.tr("%1 second", "%1 seconds", seconds).arg(seconds)
901 }
902 if (remaining == "")
903 remaining = i18n.tr("0 seconds");
904 // Translators: String like "1 hour, 2 minutes, 3 seconds remaining"
905 return i18n.tr("%1 remaining").arg(remaining);
906 }
908 stateText: {
909 switch (runningState) {
910 case Menus.TransferState.Queued:
911 return i18n.tr("In queue…");
912 case Menus.TransferState.Hashing:
913 case Menus.TransferState.Processing:
914 case Menus.TransferState.Running:
915 return timeRemaining === undefined ? i18n.tr("Downloading") : timeRemaining;
916 case Menus.TransferState.Paused:
917 return i18n.tr("Paused, tap to resume");
918 case Menus.TransferState.Canceled:
919 return i18n.tr("Canceled");
920 case Menus.TransferState.Finished:
921 return i18n.tr("Finished");
922 case Menus.TransferState.Error:
923 return i18n.tr("Failed, tap to retry");
924 }
925 return "";
926 }
928 onMenuModelChanged: {
929 loadAttributes();
930 }
931 onMenuIndexChanged: {
932 loadAttributes();
933 }
934 onTriggered: {
935 actionGroup.activateAction.activate(uid);
936 }
937 onItemRemoved: {
938 actionGroup.cancelAction.activate(uid);
939 }
941 function loadAttributes() {
942 if (!menuModel || menuIndex == -1) return;
943 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-uid': 'string'});
944 }
945 }
946 }
948 Component {
949 id: buttonSectionMenu;
951 Menus.StandardMenu {
952 objectName: "buttonSectionMenu"
953 property QtObject menuData: null
954 property var menuModel: menuFactory.menuModel
955 property int menuIndex: -1
956 property var extendedData: menuData && menuData.ext || undefined
958 iconSource: menuData && menuData.icon || ""
959 enabled: menuData && menuData.sensitive || false
960 highlightWhenPressed: false
961 text: menuData && menuData.label || ""
962 foregroundColor: theme.palette.normal.backgroundText
964 onMenuModelChanged: {
965 loadAttributes();
966 }
967 onMenuIndexChanged: {
968 loadAttributes();
969 }
970 function loadAttributes() {
971 if (!menuModel || menuIndex == -1) return;
972 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-extra-label': 'string'});
973 }
975 component: Component {
976 Button {
977 objectName: "buttonSectionMenuControl"
978 text: getExtendedProperty(extendedData, "xCanonicalExtraLabel", "")
980 onClicked: {
981 menuModel.activate(menuIndex);
982 }
983 }
984 }
985 }
986 }
988 function load(modelData, context) {
989 // tweak indicator-session items
990 if (context === "indicator-session") {
991 if ((modelData.action === "indicator.logout" || modelData.action === "indicator.suspend" || modelData.action === "indicator.hibernate" ||
992 modelData.action === "indicator.reboot")
993 && !Platform.isPC) {
994 return null; // logout, suspend and hibernate hidden on devices
995 }
996 }
998 if (modelData.type !== undefined && modelData.type !== "") {
999 var component = undefined;
1001 var contextComponents = _map[context];
1002 if (contextComponents !== undefined) {
1003 component = contextComponents[modelData.type];
1006 if (component === undefined) {
1007 component = _map["default"][modelData.type];
1009 if (component !== undefined) {
1010 return component;
1012 console.debug("Don't know how to make " + modelData.type + " for " + context);
1014 if (modelData.isCheck || modelData.isRadio) {
1015 return checkableMenu;
1017 if (modelData.isSeparator) {
1018 return separatorMenu;
1020 return standardMenu;