on 19a9ecd help sign in
unity8/qml/Panel/Indicators/IndicatorMenuItemFactory.qml
1113 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
28Object {
29 id: menuFactory
31 property string indicator
32 property var rootModel: null
33 property var menuModel: null
35 property var _userMap: null
36 readonly property var _typeToComponent: {
37 "default": {
38 "unity.widgets.systemsettings.tablet.volumecontrol" : sliderMenu,
39 "unity.widgets.systemsettings.tablet.switch" : switchMenu,
41 "com.canonical.indicator.button" : buttonMenu,
42 "com.canonical.indicator.div" : separatorMenu,
43 "com.canonical.indicator.section" : sectionMenu,
44 "com.canonical.indicator.progress" : progressMenu,
45 "com.canonical.indicator.slider" : sliderMenu,
46 "com.canonical.indicator.switch" : switchMenu,
47 "com.canonical.indicator.alarm" : alarmMenu,
48 "com.canonical.indicator.appointment" : appointmentMenu,
49 "com.canonical.indicator.transfer" : transferMenu,
50 "com.canonical.indicator.button-section" : buttonSectionMenu,
51 "com.canonical.indicator.link" : linkMenu,
53 "com.canonical.indicator.messages.messageitem" : messageItem,
54 "com.canonical.indicator.messages.sourceitem" : groupedMessage,
56 "com.canonical.unity.slider" : sliderMenu,
57 "com.canonical.unity.switch" : switchMenu,
59 "com.canonical.unity.media-player" : mediaPayerMenu,
60 "com.canonical.unity.playback-item" : playbackItemMenu,
62 "unity.widgets.systemsettings.tablet.wifisection" : wifiSection,
63 "unity.widgets.systemsettings.tablet.accesspoint" : accessPoint,
64 "com.canonical.indicator.network.modeminfoitem" : modeminfoitem,
66 "com.canonical.indicator.calendar": calendarMenu,
67 "com.canonical.indicator.location": timezoneMenu,
68 },
69 "indicator-session": {
70 "indicator.user-menu-item": Platform.isPC ? userMenuItem : null,
71 "indicator.guest-menu-item": Platform.isPC ? userMenuItem : null,
72 "com.canonical.indicator.switch": Math.min(Screen.width, Screen.height) > units.gu(60) ? switchMenu : null // Desktop mode switch
73 },
74 "indicator-messages": {
75 "com.canonical.indicator.button": messagesButtonMenu
76 }
77 }
79 readonly property var _action_filter_map: {
80 "indicator-session": {
81 "indicator.logout": Platform.isPC ? undefined : null,
82 "indicator.suspend": Platform.isPC ? undefined : null,
83 "indicator.hibernate": Platform.isPC ? undefined : null,
84 "indicator.reboot": Platform.isPC ? undefined : null
85 },
86 "indicator-keyboard": {
87 "indicator.map": null,
88 "indicator.chart": null
89 }
90 }
92 function getComponentForIndicatorEntryType(type) {
93 var component = undefined;
94 var map = _userMap || _typeToComponent
95 var indicatorComponents = map[indicator];
97 if (type === undefined || type === "") {
98 return component
99 }
101 if (indicatorComponents !== undefined) {
102 component = indicatorComponents[type];
103 }
105 if (component === undefined) {
106 component = map["default"][type];
107 }
109 if (component === undefined) {
110 console.debug("Don't know how to make " + type + " for " + indicator);
111 }
113 return component
114 }
116 function getComponentForIndicatorEntryAction(action) {
117 var component = undefined;
118 var indicatorFilter = _action_filter_map[indicator]
120 if (action === undefined || action === "") {
121 return component
122 }
124 if (indicatorFilter !== undefined) {
125 component = indicatorFilter[action];
126 }
127 return component
128 }
130 function getExtendedProperty(object, propertyName, defaultValue) {
131 if (object && object.hasOwnProperty(propertyName)) {
132 return object[propertyName];
133 }
134 return defaultValue;
135 }
137 Component {
138 id: separatorMenu;
140 Menus.SeparatorMenu {
141 objectName: "separatorMenu"
142 }
143 }
145 Component {
146 id: sliderMenu;
148 Menus.SliderMenu {
149 id: sliderItem
150 objectName: "sliderMenu"
151 property QtObject menuData: null
152 property var menuModel: menuFactory.menuModel
153 property int menuIndex: -1
154 property var extendedData: menuData && menuData.ext || undefined
155 property var serverValue: getExtendedProperty(menuData, "actionState", undefined)
157 text: menuData && menuData.label || ""
158 minIcon: getExtendedProperty(extendedData, "minIcon", "")
159 maxIcon: getExtendedProperty(extendedData, "maxIcon", "")
161 minimumValue: getExtendedProperty(extendedData, "minValue", 0.0)
162 maximumValue: {
163 var maximum = getExtendedProperty(extendedData, "maxValue", 1.0);
164 if (maximum <= minimumValue) {
165 return minimumValue + 1;
166 }
167 return maximum;
168 }
169 enabled: menuData && menuData.sensitive || false
170 highlightWhenPressed: false
172 onMenuModelChanged: {
173 loadAttributes();
174 }
175 onMenuIndexChanged: {
176 loadAttributes();
177 }
179 function loadAttributes() {
180 if (!menuModel || menuIndex == -1) return;
181 menuModel.loadExtendedAttributes(menuIndex, {'min-value': 'double',
182 'max-value': 'double',
183 'min-icon': 'icon',
184 'max-icon': 'icon',
185 'x-canonical-sync-action': 'string'});
186 }
188 ServerPropertySynchroniser {
189 id: sliderPropertySync
190 objectName: "sync"
191 syncTimeout: Utils.Constants.indicatorValueTimeout
192 bufferedSyncTimeout: true
193 maximumWaitBufferInterval: 16
195 serverTarget: sliderItem
196 serverProperty: "serverValue"
197 userTarget: sliderItem
198 userProperty: "value"
200 onSyncTriggered: menuModel.changeState(menuIndex, value)
201 }
203 UnityMenuAction {
204 model: menuModel
205 index: menuIndex
206 name: getExtendedProperty(extendedData, "xCanonicalSyncAction", "")
207 onStateChanged: {
208 sliderPropertySync.reset();
209 sliderPropertySync.updateUserValue();
210 }
211 }
212 }
213 }
215 Component {
216 id: buttonMenu;
218 Menus.ButtonMenu {
219 objectName: "buttonMenu"
220 property QtObject menuData: null
221 property var menuModel: menuFactory.menuModel
222 property int menuIndex: -1
224 buttonText: menuData && menuData.label || ""
225 enabled: menuData && menuData.sensitive || false
226 highlightWhenPressed: false
228 onTriggered: {
229 menuModel.activate(menuIndex);
230 }
231 }
232 }
234 Component {
235 id: messagesButtonMenu;
237 Menus.BaseLayoutMenu {
238 objectName: "messagesButtonMenu"
239 property QtObject menuData: null
240 property var menuModel: menuFactory.menuModel
241 property int menuIndex: -1
243 highlightWhenPressed: false
244 enabled: menuData && menuData.sensitive || false
245 text: menuData && menuData.label || ""
246 title.color: theme.palette.selected.backgroundText
247 title.horizontalAlignment: Text.AlignHCenter
248 title.font.bold: true
250 onClicked: menuModel.activate(menuIndex);
251 }
252 }
254 Component {
255 id: sectionMenu;
257 Menus.SectionMenu {
258 objectName: "sectionMenu"
259 property QtObject menuData: null
260 property var menuIndex: undefined
262 text: menuData && menuData.label || ""
263 busy: false
264 }
265 }
267 Component {
268 id: progressMenu;
270 Menus.ProgressValueMenu {
271 objectName: "progressMenu"
272 property QtObject menuData: null
273 property int menuIndex: -1
275 text: menuData && menuData.label || ""
276 iconSource: menuData && menuData.icon || ""
277 value : menuData && menuData.actionState || 0.0
278 enabled: menuData && menuData.sensitive || false
279 }
280 }
282 Component {
283 id: standardMenu;
285 Menus.StandardMenu {
286 objectName: "standardMenu"
287 property QtObject menuData: null
288 property int menuIndex: -1
290 text: menuData && menuData.label || ""
291 iconSource: menuData && menuData.icon || ""
292 enabled: menuData && menuData.sensitive || false
293 highlightWhenPressed: false
295 onTriggered: {
296 menuModel.activate(menuIndex);
297 }
298 }
299 }
301 Component {
302 id: linkMenu;
304 Menus.BaseLayoutMenu {
305 objectName: "linkMenu"
306 property QtObject menuData: null
307 property int menuIndex: -1
309 text: menuData && menuData.label || ""
310 enabled: menuData && menuData.sensitive || false
311 backColor: Qt.rgba(1,1,1,0.07)
312 highlightWhenPressed: false
314 onTriggered: {
315 menuModel.activate(menuIndex);
316 }
318 slots: Icon {
319 source: {
320 if (menuData) {
321 if (menuData.icon && menuData.icon != "") {
322 return menuData.icon
323 } else if (menuData.action.indexOf("settings") > -1) {
324 return "image://theme/settings"
325 }
326 }
327 return ""
328 }
329 height: units.gu(3)
330 width: height
331 color: theme.palette.normal.backgroundText
332 SlotsLayout.position: SlotsLayout.Trailing
333 }
334 }
335 }
337 Component {
338 id: checkableMenu;
340 Menus.CheckableMenu {
341 id: checkItem
342 objectName: "checkableMenu"
343 property QtObject menuData: null
344 property int menuIndex: -1
345 property bool serverChecked: menuData && menuData.isToggled || false
347 text: menuData && menuData.label || ""
348 enabled: menuData && menuData.sensitive || false
349 checked: serverChecked
350 highlightWhenPressed: false
352 ServerPropertySynchroniser {
353 objectName: "sync"
354 syncTimeout: Utils.Constants.indicatorValueTimeout
356 serverTarget: checkItem
357 serverProperty: "serverChecked"
358 userTarget: checkItem
359 userProperty: "checked"
361 onSyncTriggered: menuModel.activate(checkItem.menuIndex)
362 }
363 }
364 }
366 Component {
367 id: radioMenu;
369 Menus.RadioMenu {
370 id: radioItem
371 objectName: "radioMenu"
372 property QtObject menuData: null
373 property int menuIndex: -1
374 property bool serverChecked: menuData && menuData.isToggled || false
376 text: menuData && menuData.label || ""
377 enabled: menuData && menuData.sensitive || false
378 checked: serverChecked
379 highlightWhenPressed: false
381 ServerPropertySynchroniser {
382 objectName: "sync"
383 syncTimeout: Utils.Constants.indicatorValueTimeout
385 serverTarget: radioItem
386 serverProperty: "serverChecked"
387 userTarget: radioItem
388 userProperty: "checked"
390 onSyncTriggered: menuModel.activate(radioItem.menuIndex)
391 }
392 }
393 }
395 Component {
396 id: switchMenu;
398 Menus.SwitchMenu {
399 id: switchItem
400 objectName: "switchMenu"
401 property QtObject menuData: null
402 property var menuModel: menuFactory.menuModel
403 property int menuIndex: -1
404 property var extendedData: menuData && menuData.ext || undefined
405 property bool serverChecked: menuData && menuData.isToggled || false
407 text: menuData && menuData.label || ""
408 iconSource: menuData && menuData.icon || ""
409 enabled: menuData && menuData.sensitive || false
410 checked: serverChecked
411 highlightWhenPressed: false
413 property var subtitleAction: UnityMenuAction {
414 model: menuModel
415 index: menuIndex
416 name: getExtendedProperty(extendedData, "xCanonicalSubtitleAction", "")
417 }
418 subtitle.text: subtitleAction.valid ? subtitleAction.state : ""
420 onMenuModelChanged: {
421 loadAttributes();
422 }
423 onMenuIndexChanged: {
424 loadAttributes();
425 }
427 function loadAttributes() {
428 if (!menuModel || menuIndex == -1) return;
429 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-subtitle-action': 'string'});
430 }
432 ServerPropertySynchroniser {
433 objectName: "sync"
434 syncTimeout: Utils.Constants.indicatorValueTimeout
436 serverTarget: switchItem
437 serverProperty: "serverChecked"
438 userTarget: switchItem
439 userProperty: "checked"
441 onSyncTriggered: menuModel.activate(switchItem.menuIndex);
442 }
443 }
444 }
446 Component {
447 id: alarmMenu;
449 Menus.EventMenu {
450 id: alarmItem
451 objectName: "alarmMenu"
452 property QtObject menuData: null
453 property var menuModel: menuFactory.menuModel
454 property int menuIndex: -1
455 property var extendedData: menuData && menuData.ext || undefined
457 readonly property date serverTime: new Date(getExtendedProperty(extendedData, "xCanonicalTime", 0) * 1000)
458 LiveTimer {
459 frequency: LiveTimer.Relative
460 relativeTime: alarmItem.serverTime
461 onTrigger: alarmItem.time = i18n.relativeDateTime(alarmItem.serverTime)
462 }
464 text: menuData && menuData.label || ""
465 iconSource: menuData && menuData.icon || "image://theme/alarm-clock"
466 time: i18n.relativeDateTime(serverTime)
467 enabled: menuData && menuData.sensitive || false
468 highlightWhenPressed: false
470 onMenuModelChanged: {
471 loadAttributes();
472 }
473 onMenuIndexChanged: {
474 loadAttributes();
475 }
476 onTriggered: {
477 menuModel.activate(menuIndex);
478 }
480 function loadAttributes() {
481 if (!menuModel || menuIndex == -1) return;
482 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-time': 'int64'});
483 }
484 }
485 }
487 Component {
488 id: appointmentMenu;
490 Menus.EventMenu {
491 id: appointmentItem
492 objectName: "appointmentMenu"
493 property QtObject menuData: null
494 property var menuModel: menuFactory.menuModel
495 property int menuIndex: -1
496 property var extendedData: menuData && menuData.ext || undefined
498 readonly property date serverTime: new Date(getExtendedProperty(extendedData, "xCanonicalTime", 0) * 1000)
500 LiveTimer {
501 frequency: LiveTimer.Relative
502 relativeTime: appointmentItem.serverTime
503 onTrigger: appointmentItem.time = i18n.relativeDateTime(appointmentItem.serverTime)
504 }
506 text: menuData && menuData.label || ""
507 iconSource: menuData && menuData.icon || "image://theme/calendar"
508 time: i18n.relativeDateTime(serverTime)
509 eventColor: getExtendedProperty(extendedData, "xCanonicalColor", Qt.rgba(0.0, 0.0, 0.0, 0.0))
510 enabled: menuData && menuData.sensitive || false
511 highlightWhenPressed: false
513 onMenuModelChanged: {
514 loadAttributes();
515 }
516 onMenuIndexChanged: {
517 loadAttributes();
518 }
519 onTriggered: {
520 menuModel.activate(menuIndex);
521 }
523 function loadAttributes() {
524 if (!menuModel || menuIndex == -1) return;
525 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-color': 'string',
526 'x-canonical-time': 'int64'});
527 }
528 }
529 }
531 Component {
532 id: userMenuItem
534 Menus.UserSessionMenu {
535 objectName: "userSessionMenu"
536 highlightWhenPressed: false
538 property QtObject menuData: null
539 property var menuModel: menuFactory.menuModel
540 property int menuIndex: -1
542 name: menuData && menuData.label || "" // label is the user's real name
543 iconSource: menuData && menuData.icon || ""
545 // would be better to compare with the logname but sadly the indicator doesn't expose that
546 active: DBusUnitySessionService.RealName() !== "" ? DBusUnitySessionService.RealName() == name
547 : DBusUnitySessionService.UserName() == name
549 onTriggered: {
550 menuModel.activate(menuIndex);
551 }
552 }
553 }
555 Component {
556 id: calendarMenu
558 Menus.CalendarMenu {
559 id: calendarItem
560 objectName: "calendarMenu"
561 focus: true
563 property QtObject menuData: null
564 property var menuModel: menuFactory.menuModel
565 property var actionState: menuData && menuData.actionState || null
566 property real calendarDay: getExtendedProperty(actionState, "calendar-day", 0)
567 property int menuIndex: -1
569 showWeekNumbers: getExtendedProperty(actionState, "show-week-numbers", false)
570 eventDays: getExtendedProperty(actionState, "appointment-days", [])
572 onCalendarDayChanged: {
573 if (calendarDay > 0) {
574 // This would trigger a selectionDateChanged signal, thus
575 // we've to avoid that the subsequent model activation
576 // would cause an infinite loop
577 modelUpdateConnections.enabled = false
578 currentDate = new Date(calendarDay * 1000)
579 modelUpdateConnections.enabled = true
580 }
581 }
583 Connections {
584 id: modelUpdateConnections
585 property bool enabled: true
586 target: (enabled && calendarItem.visible) ? calendarItem : null
588 onSelectedDateChanged: {
589 menuModel.activate(menuIndex, selectedDate.getTime() / 1000 | 0)
590 }
591 }
592 }
593 }
595 Component {
596 id: timezoneMenu
598 Menus.TimeZoneMenu {
599 id: tzMenuItem
600 objectName: "timezoneMenu"
602 property QtObject menuData: null
603 property var menuModel: menuFactory.menuModel
604 property int menuIndex: -1
605 property var extendedData: menuData && menuData.ext || undefined
606 readonly property string tz: getExtendedProperty(extendedData, "xCanonicalTimezone", "UTC")
607 property var updateTimer: Timer {
608 repeat: true
609 running: tzMenuItem.visible // only run when we're open
610 onTriggered: tzMenuItem.time = Utils.TimezoneFormatter.currentTimeInTimezone(tzMenuItem.tz)
611 }
613 city: menuData && menuData.label || ""
614 time: Utils.TimezoneFormatter.currentTimeInTimezone(tz)
615 enabled: menuData && menuData.sensitive || false
617 onMenuModelChanged: {
618 loadAttributes();
619 }
620 onMenuIndexChanged: {
621 loadAttributes();
622 }
623 onTriggered: {
624 tzActionGroup.setLocation.activate(tz);
625 }
627 QDBusActionGroup {
628 id: tzActionGroup
629 busType: DBus.SessionBus
630 busName: "com.canonical.indicator.datetime"
631 objectPath: "/com/canonical/indicator/datetime"
633 property variant setLocation: action("set-location")
635 Component.onCompleted: tzActionGroup.start()
636 }
638 function loadAttributes() {
639 if (!menuModel || menuIndex == -1) return;
640 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-timezone': 'string'});
641 }
642 }
643 }
645 Component {
646 id: wifiSection;
648 Menus.SectionMenu {
649 objectName: "wifiSection"
650 property QtObject menuData: null
651 property var menuModel: menuFactory.menuModel
652 property int menuIndex: -1
653 property var extendedData: menuData && menuData.ext || undefined
655 text: menuData && menuData.label || ""
656 busy: getExtendedProperty(extendedData, "xCanonicalBusyAction", false)
658 onMenuModelChanged: {
659 loadAttributes();
660 }
661 onMenuIndexChanged: {
662 loadAttributes();
663 }
665 function loadAttributes() {
666 if (!menuModel || menuIndex == -1) return;
667 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-busy-action': 'bool'})
668 }
669 }
670 }
672 Component {
673 id: accessPoint;
675 Menus.AccessPointMenu {
676 id: apItem
677 objectName: "accessPoint"
678 property QtObject menuData: null
679 property var menuModel: menuFactory.menuModel
680 property int menuIndex: -1
681 property var extendedData: menuData && menuData.ext || undefined
682 property bool serverChecked: menuData && menuData.isToggled || false
684 property var strengthAction: UnityMenuAction {
685 model: menuModel
686 index: menuIndex
687 name: getExtendedProperty(extendedData, "xCanonicalWifiApStrengthAction", "")
688 }
690 text: menuData && menuData.label || ""
691 enabled: menuData && menuData.sensitive || false
692 active: serverChecked
693 secure: getExtendedProperty(extendedData, "xCanonicalWifiApIsSecure", false)
694 adHoc: getExtendedProperty(extendedData, "xCanonicalWifiApIsAdhoc", false)
695 signalStrength: {
696 if (strengthAction.valid) {
697 var state = strengthAction.state; // handle both int and uchar
698 // FIXME remove the special casing when we switch to indicator-network completely
699 if (typeof state == "string") {
700 return state.charCodeAt();
701 }
702 return state;
703 }
704 return 0;
705 }
706 highlightWhenPressed: false
708 onMenuModelChanged: {
709 loadAttributes();
710 }
711 onMenuIndexChanged: {
712 loadAttributes();
713 }
715 function loadAttributes() {
716 if (!menuModel || menuIndex == -1) return;
717 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-wifi-ap-is-adhoc': 'bool',
718 'x-canonical-wifi-ap-is-secure': 'bool',
719 'x-canonical-wifi-ap-strength-action': 'string'});
720 }
722 ServerPropertySynchroniser {
723 objectName: "sync"
724 syncTimeout: Utils.Constants.indicatorValueTimeout
726 serverTarget: apItem
727 serverProperty: "serverChecked"
728 userTarget: apItem
729 userProperty: "active"
730 userTrigger: "onTriggered"
732 onSyncTriggered: menuModel.activate(apItem.menuIndex)
733 }
734 }
735 }
737 Component {
738 id: modeminfoitem;
739 Menus.ModemInfoItem {
740 objectName: "modemInfoItem"
741 property QtObject menuData: null
742 property var menuModel: menuFactory.menuModel
743 property int menuIndex: -1
744 property var extendedData: menuData && menuData.ext || undefined
745 highlightWhenPressed: false
747 property var statusLabelAction: UnityMenuAction {
748 model: menuModel
749 index: menuIndex
750 name: getExtendedProperty(extendedData, "xCanonicalModemStatusLabelAction", "")
751 }
752 statusText: statusLabelAction.valid ? statusLabelAction.state : ""
754 property var statusIconAction: UnityMenuAction {
755 model: menuModel
756 index: menuIndex
757 name: getExtendedProperty(extendedData, "xCanonicalModemStatusIconAction", "")
758 }
759 statusIcon: statusIconAction.valid ? statusIconAction.state : ""
761 property var connectivityIconAction: UnityMenuAction {
762 model: menuModel
763 index: menuIndex
764 name: getExtendedProperty(extendedData, "xCanonicalModemConnectivityIconAction", "")
765 }
766 connectivityIcon: connectivityIconAction.valid ? connectivityIconAction.state : ""
768 property var simIdentifierLabelAction: UnityMenuAction {
769 model: menuModel
770 index: menuIndex
771 name: getExtendedProperty(extendedData, "xCanonicalModemSimIdentifierLabelAction", "")
772 }
773 simIdentifierText: simIdentifierLabelAction.valid ? simIdentifierLabelAction.state : ""
775 property var roamingAction: UnityMenuAction {
776 model: menuModel
777 index: menuIndex
778 name: getExtendedProperty(extendedData, "xCanonicalModemRoamingAction", "")
779 }
780 roaming: roamingAction.valid ? roamingAction.state : false
782 property var unlockAction: UnityMenuAction {
783 model: menuModel
784 index: menuIndex
785 name: getExtendedProperty(extendedData, "xCanonicalModemLockedAction", "")
786 }
787 onUnlock: {
788 unlockAction.activate();
789 }
790 locked: unlockAction.valid ? unlockAction.state : false
792 onMenuModelChanged: {
793 loadAttributes();
794 }
795 onMenuIndexChanged: {
796 loadAttributes();
797 }
799 function loadAttributes() {
800 if (!menuModel || menuIndex == -1) return;
801 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-modem-status-label-action': 'string',
802 'x-canonical-modem-status-icon-action': 'string',
803 'x-canonical-modem-connectivity-icon-action': 'string',
804 'x-canonical-modem-sim-identifier-label-action': 'string',
805 'x-canonical-modem-roaming-action': 'string',
806 'x-canonical-modem-locked-action': 'string'});
807 }
808 }
809 }
811 Component {
812 id: messageItem
814 MessageMenuItemFactory {
815 objectName: "messageItem"
816 menuModel: menuFactory.menuModel
817 }
818 }
820 Component {
821 id: groupedMessage
823 Menus.GroupedMessageMenu {
824 objectName: "groupedMessage"
825 property QtObject menuData: null
826 property var menuModel: menuFactory.menuModel
827 property int menuIndex: -1
828 property var extendedData: menuData && menuData.ext || undefined
830 text: menuData && menuData.label || ""
831 iconSource: getExtendedProperty(extendedData, "icon", "image://theme/message")
832 count: menuData && menuData.actionState.length > 0 ? menuData.actionState[0] : "0"
833 enabled: menuData && menuData.sensitive || false
834 highlightWhenPressed: false
835 removable: true
837 onMenuModelChanged: {
838 loadAttributes();
839 }
840 onMenuIndexChanged: {
841 loadAttributes();
842 }
843 onClicked: {
844 menuModel.activate(menuIndex, true);
845 }
846 onDismissed: {
847 menuModel.activate(menuIndex, false);
848 }
850 function loadAttributes() {
851 if (!menuModel || menuIndex == -1) return;
852 menuModel.loadExtendedAttributes(modelIndex, {'icon': 'icon'});
853 }
854 }
855 }
857 Component {
858 id: mediaPayerMenu;
860 Menus.MediaPlayerMenu {
861 objectName: "mediaPayerMenu"
862 property QtObject menuData: null
863 property var menuModel: menuFactory.menuModel
864 property int menuIndex: -1
865 property var actionState: menuData && menuData.actionState || undefined
866 property bool running: getExtendedProperty(actionState, "running", false)
868 playerIcon: menuData && menuData.icon || "image://theme/stock_music"
869 playerName: menuData && menuData.label || i18n.tr("Nothing is playing")
871 albumArt: getExtendedProperty(actionState, "art-url", "image://theme/stock_music")
872 song: getExtendedProperty(actionState, "title", "")
873 artist: getExtendedProperty(actionState, "artist", "")
874 album: getExtendedProperty(actionState, "album", "")
875 showTrack: running && (state == "Playing" || state == "Paused")
876 state: getExtendedProperty(actionState, "state", "")
877 enabled: menuData && menuData.sensitive || false
878 highlightWhenPressed: false
880 onTriggered: {
881 model.activate(modelIndex);
882 }
883 }
884 }
886 Component {
887 id: playbackItemMenu;
889 Menus.PlaybackItemMenu {
890 objectName: "playbackItemMenu"
891 property QtObject menuData: null
892 property var menuModel: menuFactory.menuModel
893 property int menuIndex: -1
894 property var extendedData: menuData && menuData.ext || undefined
896 property var playAction: UnityMenuAction {
897 model: menuModel
898 index: menuIndex
899 name: getExtendedProperty(extendedData, "xCanonicalPlayAction", "")
900 }
901 property var nextAction: UnityMenuAction {
902 model: menuModel
903 index: menuIndex
904 name: getExtendedProperty(extendedData, "xCanonicalNextAction", "")
905 }
906 property var previousAction: UnityMenuAction {
907 model: menuModel
908 index: menuIndex
909 name: getExtendedProperty(extendedData, "xCanonicalPreviousAction", "")
910 }
912 playing: playAction.state === "Playing"
913 canPlay: playAction.valid
914 canGoNext: nextAction.valid
915 canGoPrevious: previousAction.valid
916 enabled: menuData && menuData.sensitive || false
917 highlightWhenPressed: false
919 onPlay: {
920 playAction.activate();
921 }
922 onNext: {
923 nextAction.activate();
924 }
925 onPrevious: {
926 previousAction.activate();
927 }
928 onMenuModelChanged: {
929 loadAttributes();
930 }
931 onMenuIndexChanged: {
932 loadAttributes();
933 }
935 function loadAttributes() {
936 if (!menuModel || menuIndex == -1) return;
937 menuModel.loadExtendedAttributes(modelIndex, {'x-canonical-play-action': 'string',
938 'x-canonical-next-action': 'string',
939 'x-canonical-previous-action': 'string'});
940 }
941 }
942 }
944 Component {
945 id: transferMenu
947 Menus.TransferMenu {
948 objectName: "transferMenu"
949 id: transfer
950 property QtObject menuData: null
951 property var menuModel: menuFactory.menuModel
952 property int menuIndex: -1
953 property var extendedData: menuData && menuData.ext || undefined
954 property var uid: getExtendedProperty(extendedData, "xCanonicalUid", undefined)
956 text: menuData && menuData.label || ""
957 iconSource: menuData && menuData.icon || "image://theme/transfer-none"
958 maximum: 1.0
959 enabled: menuData && menuData.sensitive || false
960 highlightWhenPressed: false
961 removable: true
962 confirmRemoval: true
964 QDBusActionGroup {
965 id: actionGroup
966 busType: 1
967 busName: rootModel.busName
968 objectPath: rootModel.actions["indicator"]
970 property var activateAction: action("activate-transfer")
971 property var cancelAction: action("cancel-transfer")
972 property var transferStateAction: uid !== undefined ? action("transfer-state."+uid) : null
974 Component.onCompleted: actionGroup.start()
975 }
977 property var transferState: {
978 if (actionGroup.transferStateAction === null) return undefined;
979 return actionGroup.transferStateAction.valid ? actionGroup.transferStateAction.state : undefined
980 }
982 property var runningState : transferState !== undefined ? transferState["state"] : undefined
983 property var secondsLeft : transferState !== undefined ? transferState["seconds-left"] : undefined
985 active: runningState !== undefined && runningState !== Menus.TransferState.Finished
986 progress: transferState !== undefined ? transferState["percent"] : 0.0
988 // TODO - Should be in the SDK
989 property var timeRemaining: {
990 if (secondsLeft === undefined) return undefined;
992 var remaining = "";
993 var hours = Math.floor(secondsLeft / (60 * 60));
994 var minutes = Math.floor(secondsLeft / 60) % 60;
995 var seconds = secondsLeft % 60;
996 if (hours > 0) {
997 remaining += i18n.tr("%1 hour", "%1 hours", hours).arg(hours)
998 }
999 if (minutes > 0) {
1000 if (remaining != "") remaining += ", ";
1001 remaining += i18n.tr("%1 minute", "%1 minutes", minutes).arg(minutes)
1003 // don't include seconds if hours > 0
1004 if (hours == 0 && minutes < 5 && seconds > 0) {
1005 if (remaining != "") remaining += ", ";
1006 remaining += i18n.tr("%1 second", "%1 seconds", seconds).arg(seconds)
1008 if (remaining == "")
1009 remaining = i18n.tr("0 seconds");
1010 // Translators: String like "1 hour, 2 minutes, 3 seconds remaining"
1011 return i18n.tr("%1 remaining").arg(remaining);
1014 stateText: {
1015 switch (runningState) {
1016 case Menus.TransferState.Queued:
1017 return i18n.tr("In queue…");
1018 case Menus.TransferState.Hashing:
1019 case Menus.TransferState.Processing:
1020 case Menus.TransferState.Running:
1021 return timeRemaining === undefined ? i18n.tr("Downloading") : timeRemaining;
1022 case Menus.TransferState.Paused:
1023 return i18n.tr("Paused, tap to resume");
1024 case Menus.TransferState.Canceled:
1025 return i18n.tr("Canceled");
1026 case Menus.TransferState.Finished:
1027 return i18n.tr("Finished");
1028 case Menus.TransferState.Error:
1029 return i18n.tr("Failed, tap to retry");
1031 return "";
1034 onMenuModelChanged: {
1035 loadAttributes();
1037 onMenuIndexChanged: {
1038 loadAttributes();
1040 onTriggered: {
1041 actionGroup.activateAction.activate(uid);
1043 onItemRemoved: {
1044 actionGroup.cancelAction.activate(uid);
1047 function loadAttributes() {
1048 if (!menuModel || menuIndex == -1) return;
1049 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-uid': 'string'});
1054 Component {
1055 id: buttonSectionMenu;
1057 Menus.ButtonMenu {
1058 objectName: "buttonSectionMenu"
1059 property QtObject menuData: null
1060 property var menuModel: menuFactory.menuModel
1061 property int menuIndex: -1
1062 property var extendedData: menuData && menuData.ext || undefined
1064 iconSource: menuData && menuData.icon || ""
1065 enabled: menuData && menuData.sensitive || false
1066 highlightWhenPressed: false
1067 text: menuData && menuData.label || ""
1068 foregroundColor: theme.palette.normal.backgroundText
1069 buttonText: getExtendedProperty(extendedData, "xCanonicalExtraLabel", "")
1071 onMenuModelChanged: {
1072 loadAttributes();
1074 onMenuIndexChanged: {
1075 loadAttributes();
1077 function loadAttributes() {
1078 if (!menuModel || menuIndex == -1) return;
1079 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-extra-label': 'string'});
1082 onButtonClicked: menuModel.activate(menuIndex);
1086 function load(modelData) {
1087 var component = getComponentForIndicatorEntryAction(modelData.action)
1088 if (component !== undefined) {
1089 return component
1092 component = getComponentForIndicatorEntryType(modelData.type)
1093 if (component !== undefined) {
1094 return component;
1097 if (modelData.isCheck) {
1098 return checkableMenu;
1100 if (modelData.isRadio) {
1101 return radioMenu;
1103 if (modelData.isSeparator) {
1104 return separatorMenu;
1106 if (modelData.action !== undefined && modelData.action.indexOf("settings") > -1) {
1107 // FIXME : At the moment, the indicators aren't using
1108 // com.canonical.indicators.link for settings menu. Need to fudge it.
1109 return linkMenu;
1111 return standardMenu;