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
22 import Ubuntu.Settings.Components 0.1
24 import Utils 0.1 as Utils
25 import Ubuntu.Components.ListItems 0.1 as ListItems
26 import Ubuntu.Components 1.1
31 property var rootModel: null
32 property var menuModel: null
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 "indicator-messages" : {
65 "com.canonical.indicator.button" : messagesButtonMenu
69 function getExtendedProperty(object, propertyName, defaultValue) {
70 if (object && object.hasOwnProperty(propertyName)) {
71 return object[propertyName];
80 objectName: "separatorMenu"
89 objectName: "sliderMenu"
90 property QtObject menuData: null
91 property var menuModel: menuFactory.menuModel
92 property int menuIndex: -1
93 property var extendedData: menuData && menuData.ext || undefined
94 property var serverValue: getExtendedProperty(menuData, "actionState", undefined)
96 text: menuData && menuData.label || ""
97 iconSource: menuData && menuData.icon || ""
98 minIcon: getExtendedProperty(extendedData, "minIcon", "")
99 maxIcon: getExtendedProperty(extendedData, "maxIcon", "")
101 minimumValue: getExtendedProperty(extendedData, "minValue", 0.0)
103 var maximum = getExtendedProperty(extendedData, "maxValue", 1.0);
104 if (maximum <= minimumValue) {
105 return minimumValue + 1;
109 enabled: menuData && menuData.sensitive || false
110 highlightWhenPressed: false
112 onMenuModelChanged: {
115 onMenuIndexChanged: {
119 function loadAttributes() {
120 if (!menuModel || menuIndex == -1) return;
121 menuModel.loadExtendedAttributes(menuIndex, {'min-value': 'double',
122 'max-value': 'double',
124 'max-icon': 'icon'});
127 ServerPropertySynchroniser {
129 syncTimeout: Utils.Constants.indicatorValueTimeout
130 bufferedSyncTimeout: true
131 maximumWaitBufferInterval: 16
133 serverTarget: sliderItem
134 serverProperty: "serverValue"
135 userTarget: sliderItem
136 userProperty: "value"
138 onSyncTriggered: menuModel.changeState(menuIndex, value)
147 objectName: "buttonMenu"
148 property QtObject menuData: null
149 property var menuModel: menuFactory.menuModel
150 property int menuIndex: -1
152 buttonText: menuData && menuData.label || ""
153 enabled: menuData && menuData.sensitive || false
154 highlightWhenPressed: false
157 menuModel.activate(menuIndex);
163 id: messagesButtonMenu;
166 objectName: "messagesButtonMenu"
167 property QtObject menuData: null
168 property var menuModel: menuFactory.menuModel
169 property int menuIndex: -1
171 implicitHeight: units.gu(5)
172 enabled: menuData && menuData.sensitive || false
176 text: menuData && menuData.label || ""
177 anchors.centerIn: parent
183 fill: buttonMenuLabel
184 margins: units.gu(-1)
186 onClicked: menuModel.activate(menuIndex);
195 objectName: "sectionMenu"
196 property QtObject menuData: null
197 property var menuIndex: undefined
199 text: menuData && menuData.label || ""
207 Menus.ProgressValueMenu {
208 objectName: "progressMenu"
209 property QtObject menuData: null
210 property int menuIndex: -1
212 text: menuData && menuData.label || ""
213 iconSource: menuData && menuData.icon || ""
214 value : menuData && menuData.actionState || 0.0
215 enabled: menuData && menuData.sensitive || false
216 highlightWhenPressed: false
224 objectName: "standardMenu"
225 property QtObject menuData: null
226 property int menuIndex: -1
228 text: menuData && menuData.label || ""
229 iconSource: menuData && menuData.icon || ""
230 enabled: menuData && menuData.sensitive || false
231 highlightWhenPressed: false
234 menuModel.activate(menuIndex);
237 // FIXME : At the moment, the indicators aren't using
238 // com.canonical.indicators.link for settings menu. Need to fudge it.
239 property bool settingsMenu: menuData && menuData.action.indexOf("settings") > -1 || false
240 backColor: settingsMenu ? Qt.rgba(1,1,1,0.07) : "transparent"
241 component: settingsMenu ? buttonForSettings : undefined
243 id: buttonForSettings
248 color: Theme.palette.selected.backgroundText
258 objectName: "linkMenu"
259 property QtObject menuData: null
260 property int menuIndex: -1
262 text: menuData && menuData.label || ""
263 iconSource: menuData && menuData.icon || ""
264 enabled: menuData && menuData.sensitive || false
265 highlightWhenPressed: false
268 menuModel.activate(menuIndex);
271 backColor: Qt.rgba(1,1,1,0.07)
273 component: menuData.icon ? icon : undefined
277 source: menuData.icon
280 color: Theme.palette.selected.backgroundText
289 Menus.CheckableMenu {
291 objectName: "checkableMenu"
292 property QtObject menuData: null
293 property int menuIndex: -1
294 property bool serverChecked: menuData && menuData.isToggled || false
296 text: menuData && menuData.label || ""
297 enabled: menuData && menuData.sensitive || false
298 checked: serverChecked
299 highlightWhenPressed: false
301 ServerPropertySynchroniser {
303 syncTimeout: Utils.Constants.indicatorValueTimeout
305 serverTarget: checkItem
306 serverProperty: "serverChecked"
307 userTarget: checkItem
308 userProperty: "checked"
310 onSyncTriggered: menuModel.activate(checkItem.menuIndex)
320 objectName: "switchMenu"
321 property QtObject menuData: null
322 property int menuIndex: -1
323 property bool serverChecked: menuData && menuData.isToggled || false
325 text: menuData && menuData.label || ""
326 iconSource: menuData && menuData.icon || ""
327 enabled: menuData && menuData.sensitive || false
328 checked: serverChecked
329 highlightWhenPressed: false
331 ServerPropertySynchroniser {
333 syncTimeout: Utils.Constants.indicatorValueTimeout
335 serverTarget: switchItem
336 serverProperty: "serverChecked"
337 userTarget: switchItem
338 userProperty: "checked"
340 onSyncTriggered: menuModel.activate(switchItem.menuIndex);
349 objectName: "alarmMenu"
350 property QtObject menuData: null
351 property var menuModel: menuFactory.menuModel
352 property int menuIndex: -1
353 property var extendedData: menuData && menuData.ext || undefined
354 // TODO - bug #1260728
355 property var timeFormatter: Utils.GDateTimeFormatter {
356 time: getExtendedProperty(extendedData, "xCanonicalTime", 0)
357 format: getExtendedProperty(extendedData, "xCanonicalTimeFormat", "")
360 text: menuData && menuData.label || ""
361 iconSource: menuData && menuData.icon || "image://theme/alarm-clock"
362 time: timeFormatter.timeString
363 enabled: menuData && menuData.sensitive || false
364 highlightWhenPressed: false
366 onMenuModelChanged: {
369 onMenuIndexChanged: {
373 menuModel.activate(menuIndex);
376 function loadAttributes() {
377 if (!menuModel || menuIndex == -1) return;
378 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-time': 'int64',
379 'x-canonical-time-format': 'string'});
388 objectName: "appointmentMenu"
389 property QtObject menuData: null
390 property var menuModel: menuFactory.menuModel
391 property int menuIndex: -1
392 property var extendedData: menuData && menuData.ext || undefined
393 // TODO - bug #1260728
394 property var timeFormatter: Utils.GDateTimeFormatter {
395 time: getExtendedProperty(extendedData, "xCanonicalTime", 0)
396 format: getExtendedProperty(extendedData, "xCanonicalTimeFormat", "")
399 text: menuData && menuData.label || ""
400 iconSource: menuData && menuData.icon || "image://theme/calendar"
401 time: timeFormatter.timeString
402 eventColor: getExtendedProperty(extendedData, "xCanonicalColor", Qt.rgba(0.0, 0.0, 0.0, 0.0))
403 enabled: menuData && menuData.sensitive || false
404 highlightWhenPressed: false
406 onMenuModelChanged: {
409 onMenuIndexChanged: {
413 menuModel.activate(menuIndex);
416 function loadAttributes() {
417 if (!menuModel || menuIndex == -1) return;
418 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-color': 'string',
419 'x-canonical-time': 'int64',
420 'x-canonical-time-format': 'string'});
429 objectName: "wifiSection"
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 text: menuData && menuData.label || ""
436 busy: getExtendedProperty(extendedData, "xCanonicalBusyAction", false)
438 onMenuModelChanged: {
441 onMenuIndexChanged: {
445 function loadAttributes() {
446 if (!menuModel || menuIndex == -1) return;
447 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-busy-action': 'bool'})
455 Menus.AccessPointMenu {
457 objectName: "accessPoint"
458 property QtObject menuData: null
459 property var menuModel: menuFactory.menuModel
460 property int menuIndex: -1
461 property var extendedData: menuData && menuData.ext || undefined
462 property bool serverChecked: menuData && menuData.isToggled || false
464 property var strengthAction: UnityMenuAction {
467 name: getExtendedProperty(extendedData, "xCanonicalWifiApStrengthAction", "")
470 text: menuData && menuData.label || ""
471 enabled: menuData && menuData.sensitive || false
472 active: serverChecked
473 secure: getExtendedProperty(extendedData, "xCanonicalWifiApIsSecure", false)
474 adHoc: getExtendedProperty(extendedData, "xCanonicalWifiApIsAdhoc", false)
475 signalStrength: strengthAction.valid ? strengthAction.state : 0
476 highlightWhenPressed: false
478 onMenuModelChanged: {
481 onMenuIndexChanged: {
485 function loadAttributes() {
486 if (!menuModel || menuIndex == -1) return;
487 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-wifi-ap-is-adhoc': 'bool',
488 'x-canonical-wifi-ap-is-secure': 'bool',
489 'x-canonical-wifi-ap-strength-action': 'string'});
492 ServerPropertySynchroniser {
494 syncTimeout: Utils.Constants.indicatorValueTimeout
497 serverProperty: "serverChecked"
499 userProperty: "active"
500 userTrigger: "onTriggered"
502 onSyncTriggered: menuModel.activate(apItem.menuIndex)
510 objectName: "modemInfoItem"
511 property QtObject menuData: null
512 property var menuModel: menuFactory.menuModel
513 property int menuIndex: -1
514 property var extendedData: menuData && menuData.ext || undefined
515 highlightWhenPressed: false
517 property var statusLabelAction: UnityMenuAction {
520 name: getExtendedProperty(extendedData, "xCanonicalModemStatusLabelAction", "")
522 statusText: statusLabelAction.valid ? statusLabelAction.state : ""
524 property var statusIconAction: UnityMenuAction {
527 name: getExtendedProperty(extendedData, "xCanonicalModemStatusIconAction", "")
529 statusIcon: statusIconAction.valid ? statusIconAction.state : ""
531 property var connectivityIconAction: UnityMenuAction {
534 name: getExtendedProperty(extendedData, "xCanonicalModemConnectivityIconAction", "")
536 connectivityIcon: connectivityIconAction.valid ? connectivityIconAction.state : ""
538 property var simIdentifierLabelAction: UnityMenuAction {
541 name: getExtendedProperty(extendedData, "xCanonicalModemSimIdentifierLabelAction", "")
543 simIdentifierText: simIdentifierLabelAction.valid ? simIdentifierLabelAction.state : ""
545 property var roamingAction: UnityMenuAction {
548 name: getExtendedProperty(extendedData, "xCanonicalModemRoamingAction", "")
550 roaming: roamingAction.valid ? roamingAction.state : false
552 property var unlockAction: UnityMenuAction {
555 name: getExtendedProperty(extendedData, "xCanonicalModemLockedAction", "")
558 unlockAction.activate();
560 locked: unlockAction.valid ? unlockAction.state : false
562 onMenuModelChanged: {
565 onMenuIndexChanged: {
569 function loadAttributes() {
570 if (!menuModel || menuIndex == -1) return;
571 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-modem-status-label-action': 'string',
572 'x-canonical-modem-status-icon-action': 'string',
573 'x-canonical-modem-connectivity-icon-action': 'string',
574 'x-canonical-modem-sim-identifier-label-action': 'string',
575 'x-canonical-modem-roaming-action': 'string',
576 'x-canonical-modem-locked-action': 'string'});
584 MessageMenuItemFactory {
585 objectName: "messageItem"
586 menuModel: menuFactory.menuModel
593 Menus.GroupedMessageMenu {
594 objectName: "groupedMessage"
595 property QtObject menuData: null
596 property var menuModel: menuFactory.menuModel
597 property int menuIndex: -1
598 property var extendedData: menuData && menuData.ext || undefined
600 text: menuData && menuData.label || ""
601 iconSource: getExtendedProperty(extendedData, "icon", "image://theme/message")
602 count: menuData && menuData.actionState.length > 0 ? menuData.actionState[0] : "0"
603 enabled: menuData && menuData.sensitive || false
604 highlightWhenPressed: false
607 onMenuModelChanged: {
610 onMenuIndexChanged: {
614 menuModel.activate(menuIndex, true);
617 menuModel.activate(menuIndex, false);
620 function loadAttributes() {
621 if (!menuModel || menuIndex == -1) return;
622 menuModel.loadExtendedAttributes(modelIndex, {'icon': 'icon'});
630 Menus.MediaPlayerMenu {
631 objectName: "mediaPayerMenu"
632 property QtObject menuData: null
633 property var menuModel: menuFactory.menuModel
634 property int menuIndex: -1
635 property var actionState: menuData && menuData.actionState || undefined
636 property bool running: getExtendedProperty(actionState, "running", false)
638 playerIcon: menuData && menuData.icon || "image://theme/stock_music"
639 playerName: menuData && menuData.label || i18n.tr("Nothing is playing")
641 albumArt: getExtendedProperty(actionState, "art-url", "image://theme/stock_music")
642 song: getExtendedProperty(actionState, "title", "")
643 artist: getExtendedProperty(actionState, "artist", "")
644 album: getExtendedProperty(actionState, "album", "")
645 showTrack: running && (state == "Playing" || state == "Paused")
646 state: getExtendedProperty(actionState, "state", "")
647 enabled: menuData && menuData.sensitive || false
648 highlightWhenPressed: false
652 model.activate(modelIndex);
658 id: playbackItemMenu;
660 Menus.PlaybackItemMenu {
661 objectName: "playbackItemMenu"
662 property QtObject menuData: null
663 property var menuModel: menuFactory.menuModel
664 property int menuIndex: -1
665 property var extendedData: menuData && menuData.ext || undefined
667 property var playAction: UnityMenuAction {
670 name: getExtendedProperty(extendedData, "xCanonicalPlayAction", "")
672 property var nextAction: UnityMenuAction {
675 name: getExtendedProperty(extendedData, "xCanonicalNextAction", "")
677 property var previousAction: UnityMenuAction {
680 name: getExtendedProperty(extendedData, "xCanonicalPreviousAction", "")
683 playing: playAction.state === "Playing"
684 canPlay: playAction.valid
685 canGoNext: nextAction.valid
686 canGoPrevious: previousAction.valid
687 enabled: menuData && menuData.sensitive || false
688 highlightWhenPressed: false
691 playAction.activate();
694 nextAction.activate();
697 previousAction.activate();
699 onMenuModelChanged: {
702 onMenuIndexChanged: {
706 function loadAttributes() {
707 if (!menuModel || menuIndex == -1) return;
708 menuModel.loadExtendedAttributes(modelIndex, {'x-canonical-play-action': 'string',
709 'x-canonical-next-action': 'string',
710 'x-canonical-previous-action': 'string'});
719 objectName: "transferMenu"
721 property QtObject menuData: null
722 property var menuModel: menuFactory.menuModel
723 property int menuIndex: -1
724 property var extendedData: menuData && menuData.ext || undefined
725 property var uid: getExtendedProperty(extendedData, "xCanonicalUid", undefined)
727 text: menuData && menuData.label || ""
728 iconSource: menuData && menuData.icon || "image://theme/transfer-none"
730 enabled: menuData && menuData.sensitive || false
731 highlightWhenPressed: false
738 busName: rootModel.busName
739 objectPath: rootModel.actions["indicator"]
741 property var activateAction: action("activate-transfer")
742 property var cancelAction: action("cancel-transfer")
743 property var transferStateAction: uid !== undefined ? action("transfer-state."+uid) : null
745 Component.onCompleted: actionGroup.start()
748 property var transferState: {
749 if (actionGroup.transferStateAction === null) return undefined;
750 return actionGroup.transferStateAction.valid ? actionGroup.transferStateAction.state : undefined
753 property var runningState : transferState !== undefined ? transferState["state"] : undefined
754 property var secondsLeft : transferState !== undefined ? transferState["seconds-left"] : undefined
756 active: runningState !== undefined && runningState !== Menus.TransferState.Finished
757 progress: transferState !== undefined ? transferState["percent"] : 0.0
759 // TODO - Should be in the SDK
760 property var timeRemaining: {
761 if (secondsLeft === undefined) return undefined;
764 var hours = Math.floor(secondsLeft / (60 * 60));
765 var minutes = Math.floor(secondsLeft / 60) % 60;
766 var seconds = secondsLeft % 60;
768 remaining += hours + (hours == 1 ? " hour" : " hours");
771 if (remaining != "") remaining += ", ";
772 remaining += minutes + (minutes == 1 ? " minute" : " minutes");
774 // don't include seconds if hours > 0
775 if (hours == 0 && minutes < 5 && seconds > 0) {
776 if (remaining != "") remaining += ", ";
777 remaining += seconds + (seconds == 1 ? " second" : " seconds");
780 remaining = "0 seconds";
781 return remaining + " remaining";
785 switch (runningState) {
786 case Menus.TransferState.Queued:
787 return i18n.tr("In queue…");
788 case Menus.TransferState.Hashing:
789 case Menus.TransferState.Processing:
790 case Menus.TransferState.Running:
791 return timeRemaining === undefined ? i18n.tr("Downloading") : timeRemaining;
792 case Menus.TransferState.Paused:
793 return i18n.tr("Paused, tap to resume");
794 case Menus.TransferState.Canceled:
795 return i18n.tr("Canceled");
796 case Menus.TransferState.Finished:
797 return i18n.tr("Finished");
798 case Menus.TransferState.Error:
799 return i18n.tr("Failed, tap to retry");
804 onMenuModelChanged: {
807 onMenuIndexChanged: {
811 actionGroup.activateAction.activate(uid);
814 actionGroup.cancelAction.activate(uid);
817 function loadAttributes() {
818 if (!menuModel || menuIndex == -1) return;
819 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-uid': 'string'});
825 id: buttonSectionMenu;
828 objectName: "buttonSectionMenu"
829 property QtObject menuData: null
830 property var menuModel: menuFactory.menuModel
831 property int menuIndex: -1
832 property var extendedData: menuData && menuData.ext || undefined
834 iconSource: menuData && menuData.icon || ""
835 enabled: menuData && menuData.sensitive || false
836 highlightWhenPressed: false
837 text: menuData && menuData.label || ""
838 foregroundColor: Theme.palette.normal.backgroundText
840 onMenuModelChanged: {
843 onMenuIndexChanged: {
846 function loadAttributes() {
847 if (!menuModel || menuIndex == -1) return;
848 menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-extra-label': 'string'});
851 component: Component {
853 objectName: "buttonSectionMenuControl"
854 text: getExtendedProperty(extendedData, "xCanonicalExtraLabel", "")
857 menuModel.activate(menuIndex);
864 function load(modelData, context) {
865 if (modelData.type !== undefined && modelData.type !== "") {
866 var component = undefined;
868 var contextComponents = _map[context];
869 if (contextComponents !== undefined) {
870 component = contextComponents[modelData.type];
873 if (component === undefined) {
874 component = _map["default"][modelData.type];
876 if (component !== undefined) {
879 console.debug("Don't know how to make " + modelData.type + " for " + context);
881 if (modelData.isCheck || modelData.isRadio) {
882 return checkableMenu;
884 if (modelData.isSeparator) {
885 return separatorMenu;