on ab2f849 help sign in
unity8/qml/Panel/Indicators/MenuItemFactory.qml
1116 lines 41 kB history raw
1/*
2 * Copyright 2013-2016 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 _userMap: null
35 readonly property var _typeToComponent: {
36 "default": {
37 "unity.widgets.systemsettings.tablet.volumecontrol" : sliderMenu,
38 "unity.widgets.systemsettings.tablet.switch" : switchMenu,
40 "com.canonical.indicator.button" : buttonMenu,
41 "com.canonical.indicator.div" : separatorMenu,
42 "com.canonical.indicator.section" : sectionMenu,
43 "com.canonical.indicator.progress" : progressMenu,
44 "com.canonical.indicator.slider" : sliderMenu,
45 "com.canonical.indicator.switch" : switchMenu,
46 "com.canonical.indicator.alarm" : alarmMenu,
47 "com.canonical.indicator.appointment" : appointmentMenu,
48 "com.canonical.indicator.transfer" : transferMenu,
49 "com.canonical.indicator.button-section" : buttonSectionMenu,
50 "com.canonical.indicator.link" : linkMenu,
52 "com.canonical.indicator.messages.messageitem" : messageItem,
53 "com.canonical.indicator.messages.sourceitem" : groupedMessage,
55 "com.canonical.unity.slider" : sliderMenu,
56 "com.canonical.unity.switch" : switchMenu,
58 "com.canonical.unity.media-player" : mediaPayerMenu,
59 "com.canonical.unity.playback-item" : playbackItemMenu,
61 "unity.widgets.systemsettings.tablet.wifisection" : wifiSection,
62 "unity.widgets.systemsettings.tablet.accesspoint" : accessPoint,
63 "com.canonical.indicator.network.modeminfoitem" : modeminfoitem,
65 "com.canonical.indicator.calendar": calendarMenu,
66 "com.canonical.indicator.location": timezoneMenu,
67 },
68 "indicator-session": {
69 "indicator.user-menu-item": Platform.isPC ? userMenuItem : null,
70 "indicator.guest-menu-item": Platform.isPC ? userMenuItem : null,
71 "com.canonical.indicator.switch": Math.min(Screen.width, Screen.height) > units.gu(60) ? switchMenu : null // Desktop mode switch
72 },
73 "indicator-messages": {
74 "com.canonical.indicator.button": messagesButtonMenu
75 }
76 }
78 readonly property var _action_filter_map: {
79 "indicator-session": {
80 "indicator.logout": Platform.isPC ? undefined : null,
81 "indicator.suspend": Platform.isPC ? undefined : null,
82 "indicator.hibernate": Platform.isPC ? undefined : null,
83 "indicator.reboot": Platform.isPC ? undefined : null
84 },
85 "indicator-keyboard": {
86 "indicator.map": null,
87 "indicator.chart": null
88 }
89 }
91 function getComponentForIndicatorEntryType(indicator, type) {
92 var component = undefined;
93 var map = _userMap || _typeToComponent
94 var indicatorComponents = map[indicator];
96 if (type === undefined || type === "") {
97 return component
98 }
100 if (indicatorComponents !== undefined) {
101 component = indicatorComponents[type];
102 }
104 if (component === undefined) {
105 component = map["default"][type];
106 }
108 if (component === undefined) {
109 console.debug("Don't know how to make " + type + " for " + indicator);
110 }
112 return component
113 }
115 function getComponentForIndicatorEntryAction(indicator, action) {
116 var component = undefined;
117 var indicatorFilter = _action_filter_map[indicator]
119 if (action === undefined || action === "") {
120 return component
121 }
123 if (indicatorFilter !== undefined) {
124 component = indicatorFilter[action];
125 }
126 return component
127 }
129 function getExtendedProperty(object, propertyName, defaultValue) {
130 if (object && object.hasOwnProperty(propertyName)) {
131 return object[propertyName];
132 }
133 return defaultValue;
134 }
136 Component {
137 id: separatorMenu;
139 Menus.SeparatorMenu {
140 objectName: "separatorMenu"
141 }
142 }
144 Component {
145 id: sliderMenu;
147 Menus.SliderMenu {
148 id: sliderItem
149 objectName: "sliderMenu"
150 property QtObject menuData: null
151 property var menuModel: menuFactory.menuModel
152 property int menuIndex: -1
153 property var extendedData: menuData && menuData.ext || undefined
154 property var serverValue: getExtendedProperty(menuData, "actionState", undefined)
156 text: menuData && menuData.label || ""
157 minIcon: getExtendedProperty(extendedData, "minIcon", "")
158 maxIcon: getExtendedProperty(extendedData, "maxIcon", "")
160 minimumValue: getExtendedProperty(extendedData, "minValue", 0.0)
161 maximumValue: {
162 var maximum = getExtendedProperty(extendedData, "maxValue", 1.0);
163 if (maximum <= minimumValue) {
164 return minimumValue + 1;
165 }
166 return maximum;
167 }
168 enabled: menuData && menuData.sensitive || false
169 highlightWhenPressed: false
171 onMenuModelChanged: {
172 loadAttributes();
173 }
174 onMenuIndexChanged: {
175 loadAttributes();
176 }
178 function loadAttributes() {
179 if (!menuModel || menuIndex == -1) return;
180 menuModel.loadExtendedAttributes(menuIndex, {'min-value': 'double',
181 'max-value': 'double',
182 'min-icon': 'icon',
183 'max-icon': 'icon',
184 'x-canonical-sync-action': 'string'});
185 }
187 ServerPropertySynchroniser {
188 id: sliderPropertySync
189 objectName: "sync"
190 syncTimeout: Utils.Constants.indicatorValueTimeout
191 bufferedSyncTimeout: true
192 maximumWaitBufferInterval: 16
194 serverTarget: sliderItem
195 serverProperty: "serverValue"
196 userTarget: sliderItem
197 userProperty: "value"
199 onSyncTriggered: menuModel.changeState(menuIndex, value)
200 }
202 UnityMenuAction {
203 model: menuModel
204 index: menuIndex
205 name: getExtendedProperty(extendedData, "xCanonicalSyncAction", "")
206 onStateChanged: {
207 sliderPropertySync.reset();
208 sliderPropertySync.updateUserValue();
209 }
210 }
211 }
212 }
214 Component {
215 id: buttonMenu;
217 Menus.ButtonMenu {
218 objectName: "buttonMenu"
219 property QtObject menuData: null
220 property var menuModel: menuFactory.menuModel
221 property int menuIndex: -1
223 buttonText: menuData && menuData.label || ""
224 enabled: menuData && menuData.sensitive || false
225 highlightWhenPressed: false
227 onTriggered: {
228 menuModel.activate(menuIndex);
229 }
230 }
231 }
233 Component {
234 id: messagesButtonMenu;
236 Menus.BaseLayoutMenu {
237 objectName: "messagesButtonMenu"
238 property QtObject menuData: null
239 property var menuModel: menuFactory.menuModel
240 property int menuIndex: -1
242 highlightWhenPressed: false
243 enabled: menuData && menuData.sensitive || false
244 text: menuData && menuData.label || ""
245 title.color: theme.palette.selected.backgroundText
246 title.horizontalAlignment: Text.AlignHCenter
247 title.font.bold: true
249 onClicked: menuModel.activate(menuIndex);
250 }
251 }
253 Component {
254 id: sectionMenu;
256 Menus.SectionMenu {
257 objectName: "sectionMenu"
258 property QtObject menuData: null
259 property var menuIndex: undefined
261 text: menuData && menuData.label || ""
262 busy: false
263 }
264 }
266 Component {
267 id: progressMenu;
269 Menus.ProgressValueMenu {
270 objectName: "progressMenu"
271 property QtObject menuData: null
272 property int menuIndex: -1
274 text: menuData && menuData.label || ""
275 iconSource: menuData && menuData.icon || ""
276 value : menuData && menuData.actionState || 0.0
277 enabled: menuData && menuData.sensitive || false
278 }
279 }
281 Component {
282 id: standardMenu;
284 Menus.StandardMenu {
285 objectName: "standardMenu"
286 property QtObject menuData: null
287 property int menuIndex: -1
289 text: menuData && menuData.label || ""
290 iconSource: menuData && menuData.icon || ""
291 enabled: menuData && menuData.sensitive || false
292 highlightWhenPressed: false
294 onTriggered: {
295 menuModel.activate(menuIndex);
296 }
297 }
298 }
300 Component {
301 id: linkMenu;
303 Menus.BaseLayoutMenu {
304 objectName: "linkMenu"
305 property QtObject menuData: null
306 property int menuIndex: -1
308 text: menuData && menuData.label || ""
309 enabled: menuData && menuData.sensitive || false
310 backColor: Qt.rgba(1,1,1,0.07)
311 highlightWhenPressed: false
313 onTriggered: {
314 menuModel.activate(menuIndex);
315 }
317 slots: Icon {
318 source: {
319 if (menuData) {
320 if (menuData.icon && menuData.icon != "") {
321 return menuData.icon
322 } else if (menuData.action.indexOf("settings") > -1) {
323 return "image://theme/settings"
324 }
325 }
326 return ""
327 }
328 height: units.gu(3)
329 width: height
330 color: theme.palette.normal.backgroundText
331 SlotsLayout.position: SlotsLayout.Trailing
332 }
333 }
334 }
336 Component {
337 id: checkableMenu;
339 Menus.CheckableMenu {
340 id: checkItem
341 objectName: "checkableMenu"
342 property QtObject menuData: null
343 property int menuIndex: -1
344 property bool serverChecked: menuData && menuData.isToggled || false
346 text: menuData && menuData.label || ""
347 enabled: menuData && menuData.sensitive || false
348 checked: serverChecked
349 highlightWhenPressed: false
351 ServerPropertySynchroniser {
352 objectName: "sync"
353 syncTimeout: Utils.Constants.indicatorValueTimeout
355 serverTarget: checkItem
356 serverProperty: "serverChecked"
357 userTarget: checkItem
358 userProperty: "checked"
360 onSyncTriggered: menuModel.activate(checkItem.menuIndex)
361 }
362 }
363 }
365 Component {
366 id: radioMenu;
368 Menus.RadioMenu {
369 id: radioItem
370 objectName: "radioMenu"
371 property QtObject menuData: null
372 property int menuIndex: -1
373 property bool serverChecked: menuData && menuData.isToggled || false
375 text: menuData && menuData.label || ""
376 enabled: menuData && menuData.sensitive || false
377 checked: serverChecked
378 highlightWhenPressed: false
380 ServerPropertySynchroniser {
381 objectName: "sync"
382 syncTimeout: Utils.Constants.indicatorValueTimeout
384 serverTarget: radioItem
385 serverProperty: "serverChecked"
386 userTarget: radioItem
387 userProperty: "checked"
389 onSyncTriggered: menuModel.activate(radioItem.menuIndex)
390 }
391 }
392 }
394 Component {
395 id: switchMenu;
397 Menus.SwitchMenu {
398 id: switchItem
399 objectName: "switchMenu"
400 property QtObject menuData: null
401 property var menuModel: menuFactory.menuModel
402 property int menuIndex: -1
403 property var extendedData: menuData && menuData.ext || undefined
404 property bool serverChecked: menuData && menuData.isToggled || false
406 text: menuData && menuData.label || ""
407 iconSource: menuData && menuData.icon || ""
408 enabled: menuData && menuData.sensitive || false
409 checked: serverChecked
410 highlightWhenPressed: false
412 property var subtitleAction: UnityMenuAction {
413 model: menuModel
414 index: menuIndex
415 name: getExtendedProperty(extendedData, "xCanonicalSubtitleAction", "")
416 }
417 subtitle.text: subtitleAction.valid ? subtitleAction.state : ""
419 onMenuModelChanged: {
420 loadAttributes();
421 }
422 onMenuIndexChanged: {
423 loadAttributes();
424 }
426 function loadAttributes() {
427 if (!menuModel || menuIndex == -1) return;
428 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-subtitle-action': 'string'});
429 }
431 ServerPropertySynchroniser {
432 objectName: "sync"
433 syncTimeout: Utils.Constants.indicatorValueTimeout
435 serverTarget: switchItem
436 serverProperty: "serverChecked"
437 userTarget: switchItem
438 userProperty: "checked"
440 onSyncTriggered: menuModel.activate(switchItem.menuIndex);
441 }
442 }
443 }
445 Component {
446 id: alarmMenu;
448 Menus.EventMenu {
449 id: alarmItem
450 objectName: "alarmMenu"
451 property QtObject menuData: null
452 property var menuModel: menuFactory.menuModel
453 property int menuIndex: -1
454 property var extendedData: menuData && menuData.ext || undefined
456 readonly property date serverTime: new Date(getExtendedProperty(extendedData, "xCanonicalTime", 0) * 1000)
457 LiveTimer {
458 frequency: LiveTimer.Relative
459 relativeTime: alarmItem.serverTime
460 onTrigger: alarmItem.time = i18n.relativeDateTime(alarmItem.serverTime)
461 }
463 text: menuData && menuData.label || ""
464 iconSource: menuData && menuData.icon || "image://theme/alarm-clock"
465 time: i18n.relativeDateTime(serverTime)
466 enabled: menuData && menuData.sensitive || false
467 highlightWhenPressed: false
469 onMenuModelChanged: {
470 loadAttributes();
471 }
472 onMenuIndexChanged: {
473 loadAttributes();
474 }
475 onTriggered: {
476 menuModel.activate(menuIndex);
477 }
479 function loadAttributes() {
480 if (!menuModel || menuIndex == -1) return;
481 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-time': 'int64'});
482 }
483 }
484 }
486 Component {
487 id: appointmentMenu;
489 Menus.EventMenu {
490 id: appointmentItem
491 objectName: "appointmentMenu"
492 property QtObject menuData: null
493 property var menuModel: menuFactory.menuModel
494 property int menuIndex: -1
495 property var extendedData: menuData && menuData.ext || undefined
497 readonly property date serverTime: new Date(getExtendedProperty(extendedData, "xCanonicalTime", 0) * 1000)
499 LiveTimer {
500 frequency: LiveTimer.Relative
501 relativeTime: appointmentItem.serverTime
502 onTrigger: appointmentItem.time = i18n.relativeDateTime(appointmentItem.serverTime)
503 }
505 text: menuData && menuData.label || ""
506 iconSource: menuData && menuData.icon || "image://theme/calendar"
507 time: i18n.relativeDateTime(serverTime)
508 eventColor: getExtendedProperty(extendedData, "xCanonicalColor", Qt.rgba(0.0, 0.0, 0.0, 0.0))
509 enabled: menuData && menuData.sensitive || false
510 highlightWhenPressed: false
512 onMenuModelChanged: {
513 loadAttributes();
514 }
515 onMenuIndexChanged: {
516 loadAttributes();
517 }
518 onTriggered: {
519 menuModel.activate(menuIndex);
520 }
522 function loadAttributes() {
523 if (!menuModel || menuIndex == -1) return;
524 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-color': 'string',
525 'x-canonical-time': 'int64'});
526 }
527 }
528 }
530 Component {
531 id: userMenuItem
533 Menus.UserSessionMenu {
534 objectName: "userSessionMenu"
535 highlightWhenPressed: false
537 property QtObject menuData: null
538 property var menuModel: menuFactory.menuModel
539 property int menuIndex: -1
541 name: menuData && menuData.label || "" // label is the user's real name
542 iconSource: menuData && menuData.icon || ""
544 // would be better to compare with the logname but sadly the indicator doesn't expose that
545 active: DBusUnitySessionService.RealName() !== "" ? DBusUnitySessionService.RealName() == name
546 : DBusUnitySessionService.UserName() == name
548 onTriggered: {
549 menuModel.activate(menuIndex);
550 }
551 }
552 }
554 Component {
555 id: calendarMenu
557 Menus.CalendarMenu {
558 id: calendarItem
559 objectName: "calendarMenu"
560 focus: true
562 property QtObject menuData: null
563 property var menuModel: menuFactory.menuModel
564 property var actionState: menuData && menuData.actionState || null
565 property real calendarDay: getExtendedProperty(actionState, "calendar-day", 0)
566 property int menuIndex: -1
568 showWeekNumbers: getExtendedProperty(actionState, "show-week-numbers", false)
569 eventDays: getExtendedProperty(actionState, "appointment-days", [])
571 onCalendarDayChanged: {
572 if (calendarDay > 0) {
573 // This would trigger a selectionDateChanged signal, thus
574 // we've to avoid that the subsequent model activation
575 // would cause an infinite loop
576 modelUpdateConnections.enabled = false
577 currentDate = new Date(calendarDay * 1000)
578 modelUpdateConnections.enabled = true
579 }
580 }
582 Connections {
583 id: modelUpdateConnections
584 property bool enabled: true
585 target: (enabled && calendarItem.visible) ? calendarItem : null
587 onSelectedDateChanged: {
588 menuModel.activate(menuIndex, selectedDate.getTime() / 1000 | 0)
589 }
590 }
591 }
592 }
594 Component {
595 id: timezoneMenu
597 Menus.TimeZoneMenu {
598 id: tzMenuItem
599 objectName: "timezoneMenu"
601 property QtObject menuData: null
602 property var menuModel: menuFactory.menuModel
603 property int menuIndex: -1
604 property var extendedData: menuData && menuData.ext || undefined
605 readonly property string tz: getExtendedProperty(extendedData, "xCanonicalTimezone", "UTC")
606 property var updateTimer: Timer {
607 repeat: true
608 running: tzMenuItem.visible // only run when we're open
609 onTriggered: tzMenuItem.time = Utils.TimezoneFormatter.currentTimeInTimezone(tzMenuItem.tz)
610 }
612 city: menuData && menuData.label || ""
613 time: Utils.TimezoneFormatter.currentTimeInTimezone(tz)
614 enabled: menuData && menuData.sensitive || false
616 onMenuModelChanged: {
617 loadAttributes();
618 }
619 onMenuIndexChanged: {
620 loadAttributes();
621 }
622 onTriggered: {
623 tzActionGroup.setLocation.activate(tz);
624 }
626 QDBusActionGroup {
627 id: tzActionGroup
628 busType: DBus.SessionBus
629 busName: "com.canonical.indicator.datetime"
630 objectPath: "/com/canonical/indicator/datetime"
632 property variant setLocation: action("set-location")
634 Component.onCompleted: tzActionGroup.start()
635 }
637 function loadAttributes() {
638 if (!menuModel || menuIndex == -1) return;
639 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-timezone': 'string'});
640 }
641 }
642 }
644 Component {
645 id: wifiSection;
647 Menus.SectionMenu {
648 objectName: "wifiSection"
649 property QtObject menuData: null
650 property var menuModel: menuFactory.menuModel
651 property int menuIndex: -1
652 property var extendedData: menuData && menuData.ext || undefined
654 text: menuData && menuData.label || ""
655 busy: getExtendedProperty(extendedData, "xCanonicalBusyAction", false)
657 onMenuModelChanged: {
658 loadAttributes();
659 }
660 onMenuIndexChanged: {
661 loadAttributes();
662 }
664 function loadAttributes() {
665 if (!menuModel || menuIndex == -1) return;
666 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-busy-action': 'bool'})
667 }
668 }
669 }
671 Component {
672 id: accessPoint;
674 Menus.AccessPointMenu {
675 id: apItem
676 objectName: "accessPoint"
677 property QtObject menuData: null
678 property var menuModel: menuFactory.menuModel
679 property int menuIndex: -1
680 property var extendedData: menuData && menuData.ext || undefined
681 property bool serverChecked: menuData && menuData.isToggled || false
683 property var strengthAction: UnityMenuAction {
684 model: menuModel
685 index: menuIndex
686 name: getExtendedProperty(extendedData, "xCanonicalWifiApStrengthAction", "")
687 }
689 text: menuData && menuData.label || ""
690 enabled: menuData && menuData.sensitive || false
691 active: serverChecked
692 secure: getExtendedProperty(extendedData, "xCanonicalWifiApIsSecure", false)
693 adHoc: getExtendedProperty(extendedData, "xCanonicalWifiApIsAdhoc", false)
694 signalStrength: {
695 if (strengthAction.valid) {
696 var state = strengthAction.state; // handle both int and uchar
697 // FIXME remove the special casing when we switch to indicator-network completely
698 if (typeof state == "string") {
699 return state.charCodeAt();
700 }
701 return state;
702 }
703 return 0;
704 }
705 highlightWhenPressed: false
707 onMenuModelChanged: {
708 loadAttributes();
709 }
710 onMenuIndexChanged: {
711 loadAttributes();
712 }
714 function loadAttributes() {
715 if (!menuModel || menuIndex == -1) return;
716 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-wifi-ap-is-adhoc': 'bool',
717 'x-canonical-wifi-ap-is-secure': 'bool',
718 'x-canonical-wifi-ap-strength-action': 'string'});
719 }
721 ServerPropertySynchroniser {
722 objectName: "sync"
723 syncTimeout: Utils.Constants.indicatorValueTimeout
725 serverTarget: apItem
726 serverProperty: "serverChecked"
727 userTarget: apItem
728 userProperty: "active"
729 userTrigger: "onTriggered"
731 onSyncTriggered: menuModel.activate(apItem.menuIndex)
732 }
733 }
734 }
736 Component {
737 id: modeminfoitem;
738 Menus.ModemInfoItem {
739 objectName: "modemInfoItem"
740 property QtObject menuData: null
741 property var menuModel: menuFactory.menuModel
742 property int menuIndex: -1
743 property var extendedData: menuData && menuData.ext || undefined
744 highlightWhenPressed: false
746 property var statusLabelAction: UnityMenuAction {
747 model: menuModel
748 index: menuIndex
749 name: getExtendedProperty(extendedData, "xCanonicalModemStatusLabelAction", "")
750 }
751 statusText: statusLabelAction.valid ? statusLabelAction.state : ""
753 property var statusIconAction: UnityMenuAction {
754 model: menuModel
755 index: menuIndex
756 name: getExtendedProperty(extendedData, "xCanonicalModemStatusIconAction", "")
757 }
758 statusIcon: statusIconAction.valid ? statusIconAction.state : ""
760 property var connectivityIconAction: UnityMenuAction {
761 model: menuModel
762 index: menuIndex
763 name: getExtendedProperty(extendedData, "xCanonicalModemConnectivityIconAction", "")
764 }
765 connectivityIcon: connectivityIconAction.valid ? connectivityIconAction.state : ""
767 property var simIdentifierLabelAction: UnityMenuAction {
768 model: menuModel
769 index: menuIndex
770 name: getExtendedProperty(extendedData, "xCanonicalModemSimIdentifierLabelAction", "")
771 }
772 simIdentifierText: simIdentifierLabelAction.valid ? simIdentifierLabelAction.state : ""
774 property var roamingAction: UnityMenuAction {
775 model: menuModel
776 index: menuIndex
777 name: getExtendedProperty(extendedData, "xCanonicalModemRoamingAction", "")
778 }
779 roaming: roamingAction.valid ? roamingAction.state : false
781 property var unlockAction: UnityMenuAction {
782 model: menuModel
783 index: menuIndex
784 name: getExtendedProperty(extendedData, "xCanonicalModemLockedAction", "")
785 }
786 onUnlock: {
787 unlockAction.activate();
788 }
789 locked: unlockAction.valid ? unlockAction.state : false
791 onMenuModelChanged: {
792 loadAttributes();
793 }
794 onMenuIndexChanged: {
795 loadAttributes();
796 }
798 function loadAttributes() {
799 if (!menuModel || menuIndex == -1) return;
800 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-modem-status-label-action': 'string',
801 'x-canonical-modem-status-icon-action': 'string',
802 'x-canonical-modem-connectivity-icon-action': 'string',
803 'x-canonical-modem-sim-identifier-label-action': 'string',
804 'x-canonical-modem-roaming-action': 'string',
805 'x-canonical-modem-locked-action': 'string'});
806 }
807 }
808 }
810 Component {
811 id: messageItem
813 MessageMenuItemFactory {
814 objectName: "messageItem"
815 menuModel: menuFactory.menuModel
816 }
817 }
819 Component {
820 id: groupedMessage
822 Menus.GroupedMessageMenu {
823 objectName: "groupedMessage"
824 property QtObject menuData: null
825 property var menuModel: menuFactory.menuModel
826 property int menuIndex: -1
827 property var extendedData: menuData && menuData.ext || undefined
829 text: menuData && menuData.label || ""
830 iconSource: getExtendedProperty(extendedData, "icon", "image://theme/message")
831 count: menuData && menuData.actionState.length > 0 ? menuData.actionState[0] : "0"
832 enabled: menuData && menuData.sensitive || false
833 highlightWhenPressed: false
834 removable: true
836 onMenuModelChanged: {
837 loadAttributes();
838 }
839 onMenuIndexChanged: {
840 loadAttributes();
841 }
842 onClicked: {
843 menuModel.activate(menuIndex, true);
844 }
845 onDismissed: {
846 menuModel.activate(menuIndex, false);
847 }
849 function loadAttributes() {
850 if (!menuModel || menuIndex == -1) return;
851 menuModel.loadExtendedAttributes(modelIndex, {'icon': 'icon'});
852 }
853 }
854 }
856 Component {
857 id: mediaPayerMenu;
859 Menus.MediaPlayerMenu {
860 objectName: "mediaPayerMenu"
861 property QtObject menuData: null
862 property var menuModel: menuFactory.menuModel
863 property int menuIndex: -1
864 property var actionState: menuData && menuData.actionState || undefined
865 property bool running: getExtendedProperty(actionState, "running", false)
867 playerIcon: menuData && menuData.icon || "image://theme/stock_music"
868 playerName: menuData && menuData.label || i18n.tr("Nothing is playing")
870 albumArt: getExtendedProperty(actionState, "art-url", "image://theme/stock_music")
871 song: getExtendedProperty(actionState, "title", "")
872 artist: getExtendedProperty(actionState, "artist", "")
873 album: getExtendedProperty(actionState, "album", "")
874 showTrack: running && (state == "Playing" || state == "Paused")
875 state: getExtendedProperty(actionState, "state", "")
876 enabled: menuData && menuData.sensitive || false
877 highlightWhenPressed: false
879 onTriggered: {
880 model.activate(modelIndex);
881 }
882 }
883 }
885 Component {
886 id: playbackItemMenu;
888 Menus.PlaybackItemMenu {
889 objectName: "playbackItemMenu"
890 property QtObject menuData: null
891 property var menuModel: menuFactory.menuModel
892 property int menuIndex: -1
893 property var extendedData: menuData && menuData.ext || undefined
895 property var playAction: UnityMenuAction {
896 model: menuModel
897 index: menuIndex
898 name: getExtendedProperty(extendedData, "xCanonicalPlayAction", "")
899 }
900 property var nextAction: UnityMenuAction {
901 model: menuModel
902 index: menuIndex
903 name: getExtendedProperty(extendedData, "xCanonicalNextAction", "")
904 }
905 property var previousAction: UnityMenuAction {
906 model: menuModel
907 index: menuIndex
908 name: getExtendedProperty(extendedData, "xCanonicalPreviousAction", "")
909 }
911 playing: playAction.state === "Playing"
912 canPlay: playAction.valid
913 canGoNext: nextAction.valid
914 canGoPrevious: previousAction.valid
915 enabled: menuData && menuData.sensitive || false
916 highlightWhenPressed: false
918 onPlay: {
919 playAction.activate();
920 }
921 onNext: {
922 nextAction.activate();
923 }
924 onPrevious: {
925 previousAction.activate();
926 }
927 onMenuModelChanged: {
928 loadAttributes();
929 }
930 onMenuIndexChanged: {
931 loadAttributes();
932 }
934 function loadAttributes() {
935 if (!menuModel || menuIndex == -1) return;
936 menuModel.loadExtendedAttributes(modelIndex, {'x-canonical-play-action': 'string',
937 'x-canonical-next-action': 'string',
938 'x-canonical-previous-action': 'string'});
939 }
940 }
941 }
943 Component {
944 id: transferMenu
946 Menus.TransferMenu {
947 objectName: "transferMenu"
948 id: transfer
949 property QtObject menuData: null
950 property var menuModel: menuFactory.menuModel
951 property int menuIndex: -1
952 property var extendedData: menuData && menuData.ext || undefined
953 property var uid: getExtendedProperty(extendedData, "xCanonicalUid", undefined)
955 text: menuData && menuData.label || ""
956 iconSource: menuData && menuData.icon || "image://theme/transfer-none"
957 maximum: 1.0
958 enabled: menuData && menuData.sensitive || false
959 highlightWhenPressed: false
960 removable: true
961 confirmRemoval: true
963 QDBusActionGroup {
964 id: actionGroup
965 busType: 1
966 busName: rootModel.busName
967 objectPath: rootModel.actions["indicator"]
969 property var activateAction: action("activate-transfer")
970 property var cancelAction: action("cancel-transfer")
971 property var transferStateAction: uid !== undefined ? action("transfer-state."+uid) : null
973 Component.onCompleted: actionGroup.start()
974 }
976 property var transferState: {
977 if (actionGroup.transferStateAction === null) return undefined;
978 return actionGroup.transferStateAction.valid ? actionGroup.transferStateAction.state : undefined
979 }
981 property var runningState : transferState !== undefined ? transferState["state"] : undefined
982 property var secondsLeft : transferState !== undefined ? transferState["seconds-left"] : undefined
984 active: runningState !== undefined && runningState !== Menus.TransferState.Finished
985 progress: transferState !== undefined ? transferState["percent"] : 0.0
987 // TODO - Should be in the SDK
988 property var timeRemaining: {
989 if (secondsLeft === undefined) return undefined;
991 var remaining = "";
992 var hours = Math.floor(secondsLeft / (60 * 60));
993 var minutes = Math.floor(secondsLeft / 60) % 60;
994 var seconds = secondsLeft % 60;
995 if (hours > 0) {
996 remaining += i18n.tr("%1 hour", "%1 hours", hours).arg(hours)
997 }
998 if (minutes > 0) {
999 if (remaining != "") remaining += ", ";
1000 remaining += i18n.tr("%1 minute", "%1 minutes", minutes).arg(minutes)
1002 // don't include seconds if hours > 0
1003 if (hours == 0 && minutes < 5 && seconds > 0) {
1004 if (remaining != "") remaining += ", ";
1005 remaining += i18n.tr("%1 second", "%1 seconds", seconds).arg(seconds)
1007 if (remaining == "")
1008 remaining = i18n.tr("0 seconds");
1009 // Translators: String like "1 hour, 2 minutes, 3 seconds remaining"
1010 return i18n.tr("%1 remaining").arg(remaining);
1013 stateText: {
1014 switch (runningState) {
1015 case Menus.TransferState.Queued:
1016 return i18n.tr("In queue…");
1017 case Menus.TransferState.Hashing:
1018 case Menus.TransferState.Processing:
1019 case Menus.TransferState.Running:
1020 return timeRemaining === undefined ? i18n.tr("Downloading") : timeRemaining;
1021 case Menus.TransferState.Paused:
1022 return i18n.tr("Paused, tap to resume");
1023 case Menus.TransferState.Canceled:
1024 return i18n.tr("Canceled");
1025 case Menus.TransferState.Finished:
1026 return i18n.tr("Finished");
1027 case Menus.TransferState.Error:
1028 return i18n.tr("Failed, tap to retry");
1030 return "";
1033 onMenuModelChanged: {
1034 loadAttributes();
1036 onMenuIndexChanged: {
1037 loadAttributes();
1039 onTriggered: {
1040 actionGroup.activateAction.activate(uid);
1042 onItemRemoved: {
1043 actionGroup.cancelAction.activate(uid);
1046 function loadAttributes() {
1047 if (!menuModel || menuIndex == -1) return;
1048 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-uid': 'string'});
1053 Component {
1054 id: buttonSectionMenu;
1056 Menus.ButtonMenu {
1057 objectName: "buttonSectionMenu"
1058 property QtObject menuData: null
1059 property var menuModel: menuFactory.menuModel
1060 property int menuIndex: -1
1061 property var extendedData: menuData && menuData.ext || undefined
1063 iconSource: menuData && menuData.icon || ""
1064 enabled: menuData && menuData.sensitive || false
1065 highlightWhenPressed: false
1066 text: menuData && menuData.label || ""
1067 foregroundColor: theme.palette.normal.backgroundText
1068 buttonText: getExtendedProperty(extendedData, "xCanonicalExtraLabel", "")
1070 onMenuModelChanged: {
1071 loadAttributes();
1073 onMenuIndexChanged: {
1074 loadAttributes();
1076 function loadAttributes() {
1077 if (!menuModel || menuIndex == -1) return;
1078 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-extra-label': 'string'});
1081 onButtonClicked: menuModel.activate(menuIndex);
1085 function load(modelData, context) {
1086 if (context && context.indexOf("fake-") == 0) {
1087 context = context.substring("fake-".length)
1090 var component = getComponentForIndicatorEntryAction(context, modelData.action)
1091 if (component !== undefined) {
1092 return component
1095 component = getComponentForIndicatorEntryType(context, modelData.type)
1096 if (component !== undefined) {
1097 return component;
1100 if (modelData.isCheck) {
1101 return checkableMenu;
1103 if (modelData.isRadio) {
1104 return radioMenu;
1106 if (modelData.isSeparator) {
1107 return separatorMenu;
1109 if (modelData.action !== undefined && modelData.action.indexOf("settings") > -1) {
1110 // FIXME : At the moment, the indicators aren't using
1111 // com.canonical.indicators.link for settings menu. Need to fudge it.
1112 return linkMenu;
1114 return standardMenu;