2 * Copyright 2013 Canonical Ltd.
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.
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.
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/>.
17 * Nick Dedekind <nick.dedekind@canonical.com>
21 import Ubuntu.Settings.Menus 0.1 as Menus
23 import Utils 0.1 as Utils
24 import Ubuntu.Components.ListItems 0.1 as ListItems
25 import Ubuntu.Components 1.1
30 property var rootModel: null
31 property var menuModel: null
35 "unity.widgets.systemsettings.tablet.volumecontrol" : sliderMenu,
36 "unity.widgets.systemsettings.tablet.switch" : switchMenu,
38 "com.canonical.indicator.button" : buttonMenu,
39 "com.canonical.indicator.div" : separatorMenu,
40 "com.canonical.indicator.section" : sectionMenu,
41 "com.canonical.indicator.progress" : progressMenu,
42 "com.canonical.indicator.slider" : sliderMenu,
43 "com.canonical.indicator.switch" : switchMenu,
44 "com.canonical.indicator.alarm" : alarmMenu,
45 "com.canonical.indicator.appointment" : appointmentMenu,
46 "com.canonical.indicator.transfer" : transferMenu,
47 "com.canonical.indicator.button-section" : buttonSectionMenu,
48 "com.canonical.indicator.link" : linkMenu,
50 "com.canonical.indicator.messages.messageitem" : messageItem,
51 "com.canonical.indicator.messages.sourceitem" : groupedMessage,
53 "com.canonical.unity.slider" : sliderMenu,
54 "com.canonical.unity.switch" : switchMenu,
56 "com.canonical.unity.media-player" : mediaPayerMenu,
57 "com.canonical.unity.playback-item" : playbackItemMenu,
59 "unity.widgets.systemsettings.tablet.wifisection" : wifiSection,
60 "unity.widgets.systemsettings.tablet.accesspoint" : accessPoint,
61 "com.canonical.indicator.network.modeminfoitem" : modeminfoitem,
63 "indicator-messages" : {
64 "com.canonical.indicator.button" : messagesButtonMenu
68 function getExtendedProperty(object, propertyName, defaultValue) {
69 if (object && object.hasOwnProperty(propertyName)) {
70 return object[propertyName];
79 objectName: "separatorMenu"
87 objectName: "sliderMenu"
88 property QtObject menuData: null
89 property var menuModel: menuFactory.menuModel
90 property int menuIndex: -1
91 property var extendedData: menuData && menuData.ext || undefined
92 property var serverValue: getExtendedProperty(menuData, "actionState", undefined)
94 text: menuData && menuData.label || ""
95 iconSource: menuData && menuData.icon || ""
96 minIcon: getExtendedProperty(extendedData, "minIcon", "")
97 maxIcon: getExtendedProperty(extendedData, "maxIcon", "")
99 minimumValue: getExtendedProperty(extendedData, "minValue", 0.0)
101 var maximum = getExtendedProperty(extendedData, "maxValue", 1.0);
102 if (maximum <= minimumValue) {
103 return minimumValue + 1;
107 enabled: menuData && menuData.sensitive || false
108 highlightWhenPressed: false
110 onMenuModelChanged: {
113 onMenuIndexChanged: {
116 onServerValueChanged: {
117 // value can be changed by slider, so a binding won't work.
118 if (serverValue !== undefined) {
123 menuModel.changeState(menuIndex, value);
126 function loadAttributes() {
127 if (!menuModel || menuIndex == -1) return;
128 menuModel.loadExtendedAttributes(menuIndex, {'min-value': 'double',
129 'max-value': 'double',
131 'max-icon': 'icon'});
140 objectName: "buttonMenu"
141 property QtObject menuData: null
142 property var menuModel: menuFactory.menuModel
143 property int menuIndex: -1
145 buttonText: menuData && menuData.label || ""
146 enabled: menuData && menuData.sensitive || false
147 highlightWhenPressed: false
150 menuModel.activate(menuIndex);
156 id: messagesButtonMenu;
159 objectName: "messagesButtonMenu"
160 property QtObject menuData: null
161 property var menuModel: menuFactory.menuModel
162 property int menuIndex: -1
164 implicitHeight: units.gu(5)
165 enabled: menuData && menuData.sensitive || false
169 text: menuData && menuData.label || ""
170 anchors.centerIn: parent
176 fill: buttonMenuLabel
177 margins: units.gu(-1)
179 onClicked: menuModel.activate(menuIndex);
188 objectName: "sectionMenu"
189 property QtObject menuData: null
190 property var menuIndex: undefined
192 text: menuData && menuData.label || ""
200 Menus.ProgressValueMenu {
201 objectName: "progressMenu"
202 property QtObject menuData: null
203 property int menuIndex: -1
205 text: menuData && menuData.label || ""
206 iconSource: menuData && menuData.icon || ""
207 value : menuData && menuData.actionState || 0.0
208 enabled: menuData && menuData.sensitive || false
209 highlightWhenPressed: false
217 objectName: "standardMenu"
218 property QtObject menuData: null
219 property int menuIndex: -1
221 text: menuData && menuData.label || ""
222 iconSource: menuData && menuData.icon || ""
223 enabled: menuData && menuData.sensitive || false
224 highlightWhenPressed: false
227 menuModel.activate(menuIndex);
230 // FIXME : At the moment, the indicators aren't using
231 // com.canonical.indicators.link for settings menu. Need to fudge it.
232 property bool settingsMenu: menuData && menuData.action.indexOf("settings") > -1 || false
233 backColor: settingsMenu ? Qt.rgba(1,1,1,0.07) : "transparent"
234 component: settingsMenu ? buttonForSettings : undefined
236 id: buttonForSettings
241 color: Theme.palette.selected.backgroundText
251 objectName: "linkMenu"
252 property QtObject menuData: null
253 property int menuIndex: -1
255 text: menuData && menuData.label || ""
256 iconSource: menuData && menuData.icon || ""
257 enabled: menuData && menuData.sensitive || false
258 highlightWhenPressed: false
261 menuModel.activate(menuIndex);
264 backColor: Qt.rgba(1,1,1,0.07)
266 component: menuData.icon ? icon : undefined
270 source: menuData.icon
273 color: Theme.palette.selected.backgroundText
282 Menus.CheckableMenu {
283 objectName: "checkableMenu"
284 property QtObject menuData: null
285 property int menuIndex: -1
287 text: menuData && menuData.label || ""
288 enabled: menuData && menuData.sensitive || false
289 checked: menuData && menuData.isToggled || false
290 highlightWhenPressed: false
293 menuModel.activate(menuIndex);
302 objectName: "switchMenu"
303 property QtObject menuData: null
304 property int menuIndex: -1
306 text: menuData && menuData.label || ""
307 iconSource: menuData && menuData.icon || ""
308 enabled: menuData && menuData.sensitive || false
309 checked: menuData && menuData.isToggled || false
310 highlightWhenPressed: false
313 menuModel.activate(menuIndex);
322 objectName: "alarmMenu"
323 property QtObject menuData: null
324 property var menuModel: menuFactory.menuModel
325 property int menuIndex: -1
326 property var extendedData: menuData && menuData.ext || undefined
327 // TODO - bug #1260728
328 property var timeFormatter: Utils.GDateTimeFormatter {
329 time: getExtendedProperty(extendedData, "xCanonicalTime", 0)
330 format: getExtendedProperty(extendedData, "xCanonicalTimeFormat", "")
333 text: menuData && menuData.label || ""
334 iconSource: menuData && menuData.icon || "image://theme/alarm-clock"
335 time: timeFormatter.timeString
336 enabled: menuData && menuData.sensitive || false
337 highlightWhenPressed: false
339 onMenuModelChanged: {
342 onMenuIndexChanged: {
346 menuModel.activate(menuIndex);
349 function loadAttributes() {
350 if (!menuModel || menuIndex == -1) return;
351 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-time': 'int64',
352 'x-canonical-time-format': 'string'});
361 objectName: "appointmentMenu"
362 property QtObject menuData: null
363 property var menuModel: menuFactory.menuModel
364 property int menuIndex: -1
365 property var extendedData: menuData && menuData.ext || undefined
366 // TODO - bug #1260728
367 property var timeFormatter: Utils.GDateTimeFormatter {
368 time: getExtendedProperty(extendedData, "xCanonicalTime", 0)
369 format: getExtendedProperty(extendedData, "xCanonicalTimeFormat", "")
372 text: menuData && menuData.label || ""
373 iconSource: menuData && menuData.icon || "image://theme/calendar"
374 time: timeFormatter.timeString
375 eventColor: getExtendedProperty(extendedData, "xCanonicalColor", Qt.rgba(0.0, 0.0, 0.0, 0.0))
376 enabled: menuData && menuData.sensitive || false
377 highlightWhenPressed: false
379 onMenuModelChanged: {
382 onMenuIndexChanged: {
386 menuModel.activate(menuIndex);
389 function loadAttributes() {
390 if (!menuModel || menuIndex == -1) return;
391 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-color': 'string',
392 'x-canonical-time': 'int64',
393 'x-canonical-time-format': 'string'});
402 objectName: "wifiSection"
403 property QtObject menuData: null
404 property var menuModel: menuFactory.menuModel
405 property int menuIndex: -1
406 property var extendedData: menuData && menuData.ext || undefined
408 text: menuData && menuData.label || ""
409 busy: getExtendedProperty(extendedData, "xCanonicalBusyAction", false)
411 onMenuModelChanged: {
414 onMenuIndexChanged: {
418 function loadAttributes() {
419 if (!menuModel || menuIndex == -1) return;
420 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-busy-action': 'bool'})
428 Menus.AccessPointMenu {
429 objectName: "accessPoint"
430 property QtObject menuData: null
431 property var menuModel: menuFactory.menuModel
432 property int menuIndex: -1
433 property var extendedData: menuData && menuData.ext || undefined
435 property var strengthAction: UnityMenuAction {
438 name: getExtendedProperty(extendedData, "xCanonicalWifiApStrengthAction", "")
441 text: menuData && menuData.label || ""
442 enabled: menuData && menuData.sensitive || false
443 active: menuData && menuData.isToggled || false
444 secure: getExtendedProperty(extendedData, "xCanonicalWifiApIsSecure", false)
445 adHoc: getExtendedProperty(extendedData, "xCanonicalWifiApIsAdhoc", false)
446 signalStrength: strengthAction.valid ? strengthAction.state : 0
447 highlightWhenPressed: false
449 onMenuModelChanged: {
452 onMenuIndexChanged: {
456 menuModel.activate(menuIndex);
459 function loadAttributes() {
460 if (!menuModel || menuIndex == -1) return;
461 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-wifi-ap-is-adhoc': 'bool',
462 'x-canonical-wifi-ap-is-secure': 'bool',
463 'x-canonical-wifi-ap-strength-action': 'string'});
471 objectName: "modemInfoItem"
472 property QtObject menuData: null
473 property var menuModel: menuFactory.menuModel
474 property int menuIndex: -1
475 property var extendedData: menuData && menuData.ext || undefined
476 highlightWhenPressed: false
478 property var statusLabelAction: UnityMenuAction {
481 name: getExtendedProperty(extendedData, "xCanonicalModemStatusLabelAction", "")
483 statusText: statusLabelAction.valid ? statusLabelAction.state : ""
485 property var statusIconAction: UnityMenuAction {
488 name: getExtendedProperty(extendedData, "xCanonicalModemStatusIconAction", "")
490 statusIcon: statusIconAction.valid ? statusIconAction.state : ""
492 property var connectivityIconAction: UnityMenuAction {
495 name: getExtendedProperty(extendedData, "xCanonicalModemConnectivityIconAction", "")
497 connectivityIcon: connectivityIconAction.valid ? connectivityIconAction.state : ""
499 property var simIdentifierLabelAction: UnityMenuAction {
502 name: getExtendedProperty(extendedData, "xCanonicalModemSimIdentifierLabelAction", "")
504 simIdentifierText: simIdentifierLabelAction.valid ? simIdentifierLabelAction.state : ""
506 property var roamingAction: UnityMenuAction {
509 name: getExtendedProperty(extendedData, "xCanonicalModemRoamingAction", "")
511 roaming: roamingAction.valid ? roamingAction.state : false
513 property var unlockAction: UnityMenuAction {
516 name: getExtendedProperty(extendedData, "xCanonicalModemLockedAction", "")
519 unlockAction.activate();
521 locked: unlockAction.valid ? unlockAction.state : false
523 onMenuModelChanged: {
526 onMenuIndexChanged: {
530 function loadAttributes() {
531 if (!menuModel || menuIndex == -1) return;
532 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-modem-status-label-action': 'string',
533 'x-canonical-modem-status-icon-action': 'string',
534 'x-canonical-modem-connectivity-icon-action': 'string',
535 'x-canonical-modem-sim-identifier-label-action': 'string',
536 'x-canonical-modem-roaming-action': 'string',
537 'x-canonical-modem-locked-action': 'string'});
545 MessageMenuItemFactory {
546 objectName: "messageItem"
547 menuModel: menuFactory.menuModel
554 Menus.GroupedMessageMenu {
555 objectName: "groupedMessage"
556 property QtObject menuData: null
557 property var menuModel: menuFactory.menuModel
558 property int menuIndex: -1
559 property var extendedData: menuData && menuData.ext || undefined
561 text: menuData && menuData.label || ""
562 iconSource: getExtendedProperty(extendedData, "icon", "image://theme/message")
563 count: menuData && menuData.actionState.length > 0 ? menuData.actionState[0] : "0"
564 enabled: menuData && menuData.sensitive || false
565 highlightWhenPressed: false
568 onMenuModelChanged: {
571 onMenuIndexChanged: {
575 menuModel.activate(menuIndex, true);
578 menuModel.activate(menuIndex, false);
581 function loadAttributes() {
582 if (!menuModel || menuIndex == -1) return;
583 menuModel.loadExtendedAttributes(modelIndex, {'icon': 'icon'});
591 Menus.MediaPlayerMenu {
592 objectName: "mediaPayerMenu"
593 property QtObject menuData: null
594 property var menuModel: menuFactory.menuModel
595 property int menuIndex: -1
596 property var actionState: menuData && menuData.actionState || undefined
597 property bool running: getExtendedProperty(actionState, "running", false)
599 playerIcon: menuData && menuData.icon || "image://theme/stock_music"
600 playerName: menuData && menuData.label || i18n.tr("Nothing is playing")
602 albumArt: getExtendedProperty(actionState, "art-url", "image://theme/stock_music")
603 song: getExtendedProperty(actionState, "title", "")
604 artist: getExtendedProperty(actionState, "artist", "")
605 album: getExtendedProperty(actionState, "album", "")
606 showTrack: running && (state == "Playing" || state == "Paused")
607 state: getExtendedProperty(actionState, "state", "")
608 enabled: menuData && menuData.sensitive || false
609 highlightWhenPressed: false
613 model.activate(modelIndex);
619 id: playbackItemMenu;
621 Menus.PlaybackItemMenu {
622 objectName: "playbackItemMenu"
623 property QtObject menuData: null
624 property var menuModel: menuFactory.menuModel
625 property int menuIndex: -1
626 property var extendedData: menuData && menuData.ext || undefined
628 property var playAction: UnityMenuAction {
631 name: getExtendedProperty(extendedData, "xCanonicalPlayAction", "")
633 property var nextAction: UnityMenuAction {
636 name: getExtendedProperty(extendedData, "xCanonicalNextAction", "")
638 property var previousAction: UnityMenuAction {
641 name: getExtendedProperty(extendedData, "xCanonicalPreviousAction", "")
644 playing: playAction.state === "Playing"
645 canPlay: playAction.valid
646 canGoNext: nextAction.valid
647 canGoPrevious: previousAction.valid
648 enabled: menuData && menuData.sensitive || false
649 highlightWhenPressed: false
652 playAction.activate();
655 nextAction.activate();
658 previousAction.activate();
660 onMenuModelChanged: {
663 onMenuIndexChanged: {
667 function loadAttributes() {
668 if (!menuModel || menuIndex == -1) return;
669 menuModel.loadExtendedAttributes(modelIndex, {'x-canonical-play-action': 'string',
670 'x-canonical-next-action': 'string',
671 'x-canonical-previous-action': 'string'});
680 objectName: "transferMenu"
682 property QtObject menuData: null
683 property var menuModel: menuFactory.menuModel
684 property int menuIndex: -1
685 property var extendedData: menuData && menuData.ext || undefined
686 property var uid: getExtendedProperty(extendedData, "xCanonicalUid", undefined)
688 text: menuData && menuData.label || ""
689 iconSource: menuData && menuData.icon || "image://theme/transfer-none"
691 enabled: menuData && menuData.sensitive || false
692 highlightWhenPressed: false
699 busName: rootModel.busName
700 objectPath: rootModel.actions["indicator"]
702 property var activateAction: action("activate-transfer")
703 property var cancelAction: action("cancel-transfer")
704 property var transferStateAction: uid !== undefined ? action("transfer-state."+uid) : null
706 Component.onCompleted: actionGroup.start()
709 property var transferState: {
710 if (actionGroup.transferStateAction === null) return undefined;
711 return actionGroup.transferStateAction.valid ? actionGroup.transferStateAction.state : undefined
714 property var runningState : transferState !== undefined ? transferState["state"] : undefined
715 property var secondsLeft : transferState !== undefined ? transferState["seconds-left"] : undefined
717 active: runningState !== undefined && runningState !== Menus.TransferState.Finished
718 progress: transferState !== undefined ? transferState["percent"] : 0.0
720 // TODO - Should be in the SDK
721 property var timeRemaining: {
722 if (secondsLeft === undefined) return undefined;
725 var hours = Math.floor(secondsLeft / (60 * 60));
726 var minutes = Math.floor(secondsLeft / 60) % 60;
727 var seconds = secondsLeft % 60;
729 remaining += hours + (hours == 1 ? " hour" : " hours");
732 if (remaining != "") remaining += ", ";
733 remaining += minutes + (minutes == 1 ? " minute" : " minutes");
735 // don't include seconds if hours > 0
736 if (hours == 0 && minutes < 5 && seconds > 0) {
737 if (remaining != "") remaining += ", ";
738 remaining += seconds + (seconds == 1 ? " second" : " seconds");
741 remaining = "0 seconds";
742 return remaining + " remaining";
746 switch (runningState) {
747 case Menus.TransferState.Queued:
748 return i18n.tr("In queue…");
749 case Menus.TransferState.Hashing:
750 case Menus.TransferState.Processing:
751 case Menus.TransferState.Running:
752 return timeRemaining === undefined ? i18n.tr("Downloading") : timeRemaining;
753 case Menus.TransferState.Paused:
754 return i18n.tr("Paused, tap to resume");
755 case Menus.TransferState.Canceled:
756 return i18n.tr("Canceled");
757 case Menus.TransferState.Finished:
758 return i18n.tr("Finished");
759 case Menus.TransferState.Error:
760 return i18n.tr("Failed, tap to retry");
765 onMenuModelChanged: {
768 onMenuIndexChanged: {
772 actionGroup.activateAction.activate(uid);
775 actionGroup.cancelAction.activate(uid);
778 function loadAttributes() {
779 if (!menuModel || menuIndex == -1) return;
780 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-uid': 'string'});
786 id: buttonSectionMenu;
789 objectName: "buttonSectionMenu"
790 property QtObject menuData: null
791 property var menuModel: menuFactory.menuModel
792 property int menuIndex: -1
793 property var extendedData: menuData && menuData.ext || undefined
795 iconSource: menuData && menuData.icon || ""
796 enabled: menuData && menuData.sensitive || false
797 highlightWhenPressed: false
798 text: menuData && menuData.label || ""
799 foregroundColor: Theme.palette.normal.backgroundText
801 onMenuModelChanged: {
804 onMenuIndexChanged: {
807 function loadAttributes() {
808 if (!menuModel || menuIndex == -1) return;
809 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-extra-label': 'string'});
812 component: Component {
814 objectName: "buttonSectionMenuControl"
815 text: getExtendedProperty(extendedData, "xCanonicalExtraLabel", "")
818 menuModel.activate(menuIndex);
825 function load(modelData, context) {
826 if (modelData.type !== undefined && modelData.type !== "") {
827 var component = undefined;
829 var contextComponents = _map[context];
830 if (contextComponents !== undefined) {
831 component = contextComponents[modelData.type];
834 if (component === undefined) {
835 component = _map["default"][modelData.type];
837 if (component !== undefined) {
840 console.debug("Don't know how to make " + modelData.type + " for " + context);
842 if (modelData.isCheck || modelData.isRadio) {
843 return checkableMenu;
845 if (modelData.isSeparator) {
846 return separatorMenu;