Unity 8
 All Classes Functions
MenuItemFactory.qml
1 /*
2  * Copyright 2013 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  *
16  * Authors:
17  * Nick Dedekind <nick.dedekind@canonical.com>
18  */
19 
20 import QtQuick 2.0
21 import Ubuntu.Settings.Menus 0.1 as Menus
22 import QMenuModel 0.1
23 import Utils 0.1 as Utils
24 import Ubuntu.Components.ListItems 0.1 as ListItems
25 import Ubuntu.Components 1.1
26 
27 Item {
28  id: menuFactory
29 
30  property var rootModel: null
31  property var menuModel: null
32 
33  property var _map: {
34  "default": {
35  "unity.widgets.systemsettings.tablet.volumecontrol" : sliderMenu,
36  "unity.widgets.systemsettings.tablet.switch" : switchMenu,
37 
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,
49 
50  "com.canonical.indicator.messages.messageitem" : messageItem,
51  "com.canonical.indicator.messages.sourceitem" : groupedMessage,
52 
53  "com.canonical.unity.slider" : sliderMenu,
54  "com.canonical.unity.switch" : switchMenu,
55 
56  "com.canonical.unity.media-player" : mediaPayerMenu,
57  "com.canonical.unity.playback-item" : playbackItemMenu,
58 
59  "unity.widgets.systemsettings.tablet.wifisection" : wifiSection,
60  "unity.widgets.systemsettings.tablet.accesspoint" : accessPoint,
61  "com.canonical.indicator.network.modeminfoitem" : modeminfoitem,
62  },
63  "indicator-messages" : {
64  "com.canonical.indicator.button" : messagesButtonMenu
65  }
66  }
67 
68  function getExtendedProperty(object, propertyName, defaultValue) {
69  if (object && object.hasOwnProperty(propertyName)) {
70  return object[propertyName];
71  }
72  return defaultValue;
73  }
74 
75  Component {
76  id: separatorMenu;
77 
78  Menus.SeparatorMenu {
79  objectName: "separatorMenu"
80  }
81  }
82 
83  Component {
84  id: sliderMenu;
85 
86  Menus.SliderMenu {
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)
93 
94  text: menuData && menuData.label || ""
95  iconSource: menuData && menuData.icon || ""
96  minIcon: getExtendedProperty(extendedData, "minIcon", "")
97  maxIcon: getExtendedProperty(extendedData, "maxIcon", "")
98 
99  minimumValue: getExtendedProperty(extendedData, "minValue", 0.0)
100  maximumValue: {
101  var maximum = getExtendedProperty(extendedData, "maxValue", 1.0);
102  if (maximum <= minimumValue) {
103  return minimumValue + 1;
104  }
105  return maximum;
106  }
107  enabled: menuData && menuData.sensitive || false
108  highlightWhenPressed: false
109 
110  onMenuModelChanged: {
111  loadAttributes();
112  }
113  onMenuIndexChanged: {
114  loadAttributes();
115  }
116  onServerValueChanged: {
117  // value can be changed by slider, so a binding won't work.
118  if (serverValue !== undefined) {
119  value = serverValue;
120  }
121  }
122  onUpdated: {
123  menuModel.changeState(menuIndex, value);
124  }
125 
126  function loadAttributes() {
127  if (!menuModel || menuIndex == -1) return;
128  menuModel.loadExtendedAttributes(menuIndex, {'min-value': 'double',
129  'max-value': 'double',
130  'min-icon': 'icon',
131  'max-icon': 'icon'});
132  }
133  }
134  }
135 
136  Component {
137  id: buttonMenu;
138 
139  Menus.ButtonMenu {
140  objectName: "buttonMenu"
141  property QtObject menuData: null
142  property var menuModel: menuFactory.menuModel
143  property int menuIndex: -1
144 
145  buttonText: menuData && menuData.label || ""
146  enabled: menuData && menuData.sensitive || false
147  highlightWhenPressed: false
148 
149  onTriggered: {
150  menuModel.activate(menuIndex);
151  }
152  }
153  }
154 
155  Component {
156  id: messagesButtonMenu;
157 
158  Item {
159  objectName: "messagesButtonMenu"
160  property QtObject menuData: null
161  property var menuModel: menuFactory.menuModel
162  property int menuIndex: -1
163 
164  implicitHeight: units.gu(5)
165  enabled: menuData && menuData.sensitive || false
166 
167  Label {
168  id: buttonMenuLabel
169  text: menuData && menuData.label || ""
170  anchors.centerIn: parent
171  font.bold: true
172  }
173 
174  MouseArea {
175  anchors {
176  fill: buttonMenuLabel
177  margins: units.gu(-1)
178  }
179  onClicked: menuModel.activate(menuIndex);
180  }
181  }
182  }
183 
184  Component {
185  id: sectionMenu;
186 
187  Menus.SectionMenu {
188  objectName: "sectionMenu"
189  property QtObject menuData: null
190  property var menuIndex: undefined
191 
192  text: menuData && menuData.label || ""
193  busy: false
194  }
195  }
196 
197  Component {
198  id: progressMenu;
199 
200  Menus.ProgressValueMenu {
201  objectName: "progressMenu"
202  property QtObject menuData: null
203  property int menuIndex: -1
204 
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
210  }
211  }
212 
213  Component {
214  id: standardMenu;
215 
216  Menus.StandardMenu {
217  objectName: "standardMenu"
218  property QtObject menuData: null
219  property int menuIndex: -1
220 
221  text: menuData && menuData.label || ""
222  iconSource: menuData && menuData.icon || ""
223  enabled: menuData && menuData.sensitive || false
224  highlightWhenPressed: false
225 
226  onTriggered: {
227  menuModel.activate(menuIndex);
228  }
229 
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
235  Component {
236  id: buttonForSettings
237  Icon {
238  name: "settings"
239  height: units.gu(3)
240  width: height
241  color: Theme.palette.selected.backgroundText
242  }
243  }
244  }
245  }
246 
247  Component {
248  id: linkMenu;
249 
250  Menus.StandardMenu {
251  objectName: "linkMenu"
252  property QtObject menuData: null
253  property int menuIndex: -1
254 
255  text: menuData && menuData.label || ""
256  iconSource: menuData && menuData.icon || ""
257  enabled: menuData && menuData.sensitive || false
258  highlightWhenPressed: false
259 
260  onTriggered: {
261  menuModel.activate(menuIndex);
262  }
263 
264  backColor: Qt.rgba(1,1,1,0.07)
265 
266  component: menuData.icon ? icon : undefined
267  Component {
268  id: icon
269  Icon {
270  source: menuData.icon
271  height: units.gu(3)
272  width: height
273  color: Theme.palette.selected.backgroundText
274  }
275  }
276  }
277  }
278 
279  Component {
280  id: checkableMenu;
281 
282  Menus.CheckableMenu {
283  objectName: "checkableMenu"
284  property QtObject menuData: null
285  property int menuIndex: -1
286  property bool serverChecked: menuData && menuData.isToggled || false
287 
288  text: menuData && menuData.label || ""
289  enabled: menuData && menuData.sensitive || false
290  checked: serverChecked
291  highlightWhenPressed: false
292 
293  onServerCheckedChanged: {
294  // value can be changed by menu, so a binding won't work.
295  checked = serverChecked;
296  }
297  onTriggered: {
298  menuModel.activate(menuIndex);
299  }
300  }
301  }
302 
303  Component {
304  id: switchMenu;
305 
306  Menus.SwitchMenu {
307  objectName: "switchMenu"
308  property QtObject menuData: null
309  property int menuIndex: -1
310  property bool serverChecked: menuData && menuData.isToggled || false
311 
312  text: menuData && menuData.label || ""
313  iconSource: menuData && menuData.icon || ""
314  enabled: menuData && menuData.sensitive || false
315  checked: serverChecked
316  highlightWhenPressed: false
317 
318  onServerCheckedChanged: {
319  // value can be changed by menu, so a binding won't work.
320  checked = serverChecked;
321  }
322  onTriggered: {
323  menuModel.activate(menuIndex);
324  }
325  }
326  }
327 
328  Component {
329  id: alarmMenu;
330 
331  Menus.EventMenu {
332  objectName: "alarmMenu"
333  property QtObject menuData: null
334  property var menuModel: menuFactory.menuModel
335  property int menuIndex: -1
336  property var extendedData: menuData && menuData.ext || undefined
337  // TODO - bug #1260728
338  property var timeFormatter: Utils.GDateTimeFormatter {
339  time: getExtendedProperty(extendedData, "xCanonicalTime", 0)
340  format: getExtendedProperty(extendedData, "xCanonicalTimeFormat", "")
341  }
342 
343  text: menuData && menuData.label || ""
344  iconSource: menuData && menuData.icon || "image://theme/alarm-clock"
345  time: timeFormatter.timeString
346  enabled: menuData && menuData.sensitive || false
347  highlightWhenPressed: false
348 
349  onMenuModelChanged: {
350  loadAttributes();
351  }
352  onMenuIndexChanged: {
353  loadAttributes();
354  }
355  onTriggered: {
356  menuModel.activate(menuIndex);
357  }
358 
359  function loadAttributes() {
360  if (!menuModel || menuIndex == -1) return;
361  menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-time': 'int64',
362  'x-canonical-time-format': 'string'});
363  }
364  }
365  }
366 
367  Component {
368  id: appointmentMenu;
369 
370  Menus.EventMenu {
371  objectName: "appointmentMenu"
372  property QtObject menuData: null
373  property var menuModel: menuFactory.menuModel
374  property int menuIndex: -1
375  property var extendedData: menuData && menuData.ext || undefined
376  // TODO - bug #1260728
377  property var timeFormatter: Utils.GDateTimeFormatter {
378  time: getExtendedProperty(extendedData, "xCanonicalTime", 0)
379  format: getExtendedProperty(extendedData, "xCanonicalTimeFormat", "")
380  }
381 
382  text: menuData && menuData.label || ""
383  iconSource: menuData && menuData.icon || "image://theme/calendar"
384  time: timeFormatter.timeString
385  eventColor: getExtendedProperty(extendedData, "xCanonicalColor", Qt.rgba(0.0, 0.0, 0.0, 0.0))
386  enabled: menuData && menuData.sensitive || false
387  highlightWhenPressed: false
388 
389  onMenuModelChanged: {
390  loadAttributes();
391  }
392  onMenuIndexChanged: {
393  loadAttributes();
394  }
395  onTriggered: {
396  menuModel.activate(menuIndex);
397  }
398 
399  function loadAttributes() {
400  if (!menuModel || menuIndex == -1) return;
401  menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-color': 'string',
402  'x-canonical-time': 'int64',
403  'x-canonical-time-format': 'string'});
404  }
405  }
406  }
407 
408  Component {
409  id: wifiSection;
410 
411  Menus.SectionMenu {
412  objectName: "wifiSection"
413  property QtObject menuData: null
414  property var menuModel: menuFactory.menuModel
415  property int menuIndex: -1
416  property var extendedData: menuData && menuData.ext || undefined
417 
418  text: menuData && menuData.label || ""
419  busy: getExtendedProperty(extendedData, "xCanonicalBusyAction", false)
420 
421  onMenuModelChanged: {
422  loadAttributes();
423  }
424  onMenuIndexChanged: {
425  loadAttributes();
426  }
427 
428  function loadAttributes() {
429  if (!menuModel || menuIndex == -1) return;
430  menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-busy-action': 'bool'})
431  }
432  }
433  }
434 
435  Component {
436  id: accessPoint;
437 
438  Menus.AccessPointMenu {
439  objectName: "accessPoint"
440  property QtObject menuData: null
441  property var menuModel: menuFactory.menuModel
442  property int menuIndex: -1
443  property var extendedData: menuData && menuData.ext || undefined
444  property bool serverChecked: menuData && menuData.isToggled || false
445 
446  property var strengthAction: UnityMenuAction {
447  model: menuModel
448  index: menuIndex
449  name: getExtendedProperty(extendedData, "xCanonicalWifiApStrengthAction", "")
450  }
451 
452  text: menuData && menuData.label || ""
453  enabled: menuData && menuData.sensitive || false
454  active: serverChecked
455  secure: getExtendedProperty(extendedData, "xCanonicalWifiApIsSecure", false)
456  adHoc: getExtendedProperty(extendedData, "xCanonicalWifiApIsAdhoc", false)
457  signalStrength: strengthAction.valid ? strengthAction.state : 0
458  highlightWhenPressed: false
459 
460  onServerCheckedChanged: {
461  // value can be changed by menu, so a binding won't work.
462  active = serverChecked;
463  }
464  onMenuModelChanged: {
465  loadAttributes();
466  }
467  onMenuIndexChanged: {
468  loadAttributes();
469  }
470  onTriggered: {
471  menuModel.activate(menuIndex);
472  }
473 
474  function loadAttributes() {
475  if (!menuModel || menuIndex == -1) return;
476  menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-wifi-ap-is-adhoc': 'bool',
477  'x-canonical-wifi-ap-is-secure': 'bool',
478  'x-canonical-wifi-ap-strength-action': 'string'});
479  }
480  }
481  }
482 
483  Component {
484  id: modeminfoitem;
485  ModemInfoItem {
486  objectName: "modemInfoItem"
487  property QtObject menuData: null
488  property var menuModel: menuFactory.menuModel
489  property int menuIndex: -1
490  property var extendedData: menuData && menuData.ext || undefined
491  highlightWhenPressed: false
492 
493  property var statusLabelAction: UnityMenuAction {
494  model: menuModel
495  index: menuIndex
496  name: getExtendedProperty(extendedData, "xCanonicalModemStatusLabelAction", "")
497  }
498  statusText: statusLabelAction.valid ? statusLabelAction.state : ""
499 
500  property var statusIconAction: UnityMenuAction {
501  model: menuModel
502  index: menuIndex
503  name: getExtendedProperty(extendedData, "xCanonicalModemStatusIconAction", "")
504  }
505  statusIcon: statusIconAction.valid ? statusIconAction.state : ""
506 
507  property var connectivityIconAction: UnityMenuAction {
508  model: menuModel
509  index: menuIndex
510  name: getExtendedProperty(extendedData, "xCanonicalModemConnectivityIconAction", "")
511  }
512  connectivityIcon: connectivityIconAction.valid ? connectivityIconAction.state : ""
513 
514  property var simIdentifierLabelAction: UnityMenuAction {
515  model: menuModel
516  index: menuIndex
517  name: getExtendedProperty(extendedData, "xCanonicalModemSimIdentifierLabelAction", "")
518  }
519  simIdentifierText: simIdentifierLabelAction.valid ? simIdentifierLabelAction.state : ""
520 
521  property var roamingAction: UnityMenuAction {
522  model: menuModel
523  index: menuIndex
524  name: getExtendedProperty(extendedData, "xCanonicalModemRoamingAction", "")
525  }
526  roaming: roamingAction.valid ? roamingAction.state : false
527 
528  property var unlockAction: UnityMenuAction {
529  model: menuModel
530  index: menuIndex
531  name: getExtendedProperty(extendedData, "xCanonicalModemLockedAction", "")
532  }
533  onUnlock: {
534  unlockAction.activate();
535  }
536  locked: unlockAction.valid ? unlockAction.state : false
537 
538  onMenuModelChanged: {
539  loadAttributes();
540  }
541  onMenuIndexChanged: {
542  loadAttributes();
543  }
544 
545  function loadAttributes() {
546  if (!menuModel || menuIndex == -1) return;
547  menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-modem-status-label-action': 'string',
548  'x-canonical-modem-status-icon-action': 'string',
549  'x-canonical-modem-connectivity-icon-action': 'string',
550  'x-canonical-modem-sim-identifier-label-action': 'string',
551  'x-canonical-modem-roaming-action': 'string',
552  'x-canonical-modem-locked-action': 'string'});
553  }
554  }
555  }
556 
557  Component {
558  id: messageItem
559 
560  MessageMenuItemFactory {
561  objectName: "messageItem"
562  menuModel: menuFactory.menuModel
563  }
564  }
565 
566  Component {
567  id: groupedMessage
568 
569  Menus.GroupedMessageMenu {
570  objectName: "groupedMessage"
571  property QtObject menuData: null
572  property var menuModel: menuFactory.menuModel
573  property int menuIndex: -1
574  property var extendedData: menuData && menuData.ext || undefined
575 
576  text: menuData && menuData.label || ""
577  iconSource: getExtendedProperty(extendedData, "icon", "image://theme/message")
578  count: menuData && menuData.actionState.length > 0 ? menuData.actionState[0] : "0"
579  enabled: menuData && menuData.sensitive || false
580  highlightWhenPressed: false
581  removable: true
582 
583  onMenuModelChanged: {
584  loadAttributes();
585  }
586  onMenuIndexChanged: {
587  loadAttributes();
588  }
589  onClicked: {
590  menuModel.activate(menuIndex, true);
591  }
592  onDismissed: {
593  menuModel.activate(menuIndex, false);
594  }
595 
596  function loadAttributes() {
597  if (!menuModel || menuIndex == -1) return;
598  menuModel.loadExtendedAttributes(modelIndex, {'icon': 'icon'});
599  }
600  }
601  }
602 
603  Component {
604  id: mediaPayerMenu;
605 
606  Menus.MediaPlayerMenu {
607  objectName: "mediaPayerMenu"
608  property QtObject menuData: null
609  property var menuModel: menuFactory.menuModel
610  property int menuIndex: -1
611  property var actionState: menuData && menuData.actionState || undefined
612  property bool running: getExtendedProperty(actionState, "running", false)
613 
614  playerIcon: menuData && menuData.icon || "image://theme/stock_music"
615  playerName: menuData && menuData.label || i18n.tr("Nothing is playing")
616 
617  albumArt: getExtendedProperty(actionState, "art-url", "image://theme/stock_music")
618  song: getExtendedProperty(actionState, "title", "")
619  artist: getExtendedProperty(actionState, "artist", "")
620  album: getExtendedProperty(actionState, "album", "")
621  showTrack: running && (state == "Playing" || state == "Paused")
622  state: getExtendedProperty(actionState, "state", "")
623  enabled: menuData && menuData.sensitive || false
624  highlightWhenPressed: false
625  showDivider: false
626 
627  onTriggered: {
628  model.activate(modelIndex);
629  }
630  }
631  }
632 
633  Component {
634  id: playbackItemMenu;
635 
636  Menus.PlaybackItemMenu {
637  objectName: "playbackItemMenu"
638  property QtObject menuData: null
639  property var menuModel: menuFactory.menuModel
640  property int menuIndex: -1
641  property var extendedData: menuData && menuData.ext || undefined
642 
643  property var playAction: UnityMenuAction {
644  model: menuModel
645  index: menuIndex
646  name: getExtendedProperty(extendedData, "xCanonicalPlayAction", "")
647  }
648  property var nextAction: UnityMenuAction {
649  model: menuModel
650  index: menuIndex
651  name: getExtendedProperty(extendedData, "xCanonicalNextAction", "")
652  }
653  property var previousAction: UnityMenuAction {
654  model: menuModel
655  index: menuIndex
656  name: getExtendedProperty(extendedData, "xCanonicalPreviousAction", "")
657  }
658 
659  playing: playAction.state === "Playing"
660  canPlay: playAction.valid
661  canGoNext: nextAction.valid
662  canGoPrevious: previousAction.valid
663  enabled: menuData && menuData.sensitive || false
664  highlightWhenPressed: false
665 
666  onPlay: {
667  playAction.activate();
668  }
669  onNext: {
670  nextAction.activate();
671  }
672  onPrevious: {
673  previousAction.activate();
674  }
675  onMenuModelChanged: {
676  loadAttributes();
677  }
678  onMenuIndexChanged: {
679  loadAttributes();
680  }
681 
682  function loadAttributes() {
683  if (!menuModel || menuIndex == -1) return;
684  menuModel.loadExtendedAttributes(modelIndex, {'x-canonical-play-action': 'string',
685  'x-canonical-next-action': 'string',
686  'x-canonical-previous-action': 'string'});
687  }
688  }
689  }
690 
691  Component {
692  id: transferMenu
693 
694  Menus.TransferMenu {
695  objectName: "transferMenu"
696  id: transfer
697  property QtObject menuData: null
698  property var menuModel: menuFactory.menuModel
699  property int menuIndex: -1
700  property var extendedData: menuData && menuData.ext || undefined
701  property var uid: getExtendedProperty(extendedData, "xCanonicalUid", undefined)
702 
703  text: menuData && menuData.label || ""
704  iconSource: menuData && menuData.icon || "image://theme/transfer-none"
705  maximum: 1.0
706  enabled: menuData && menuData.sensitive || false
707  highlightWhenPressed: false
708  removable: true
709  confirmRemoval: true
710 
711  QDBusActionGroup {
712  id: actionGroup
713  busType: 1
714  busName: rootModel.busName
715  objectPath: rootModel.actions["indicator"]
716 
717  property var activateAction: action("activate-transfer")
718  property var cancelAction: action("cancel-transfer")
719  property var transferStateAction: uid !== undefined ? action("transfer-state."+uid) : null
720 
721  Component.onCompleted: actionGroup.start()
722  }
723 
724  property var transferState: {
725  if (actionGroup.transferStateAction === null) return undefined;
726  return actionGroup.transferStateAction.valid ? actionGroup.transferStateAction.state : undefined
727  }
728 
729  property var runningState : transferState !== undefined ? transferState["state"] : undefined
730  property var secondsLeft : transferState !== undefined ? transferState["seconds-left"] : undefined
731 
732  active: runningState !== undefined && runningState !== Menus.TransferState.Finished
733  progress: transferState !== undefined ? transferState["percent"] : 0.0
734 
735  // TODO - Should be in the SDK
736  property var timeRemaining: {
737  if (secondsLeft === undefined) return undefined;
738 
739  var remaining = "";
740  var hours = Math.floor(secondsLeft / (60 * 60));
741  var minutes = Math.floor(secondsLeft / 60) % 60;
742  var seconds = secondsLeft % 60;
743  if (hours > 0) {
744  remaining += hours + (hours == 1 ? " hour" : " hours");
745  }
746  if (minutes > 0) {
747  if (remaining != "") remaining += ", ";
748  remaining += minutes + (minutes == 1 ? " minute" : " minutes");
749  }
750  // don't include seconds if hours > 0
751  if (hours == 0 && minutes < 5 && seconds > 0) {
752  if (remaining != "") remaining += ", ";
753  remaining += seconds + (seconds == 1 ? " second" : " seconds");
754  }
755  if (remaining == "")
756  remaining = "0 seconds";
757  return remaining + " remaining";
758  }
759 
760  stateText: {
761  switch (runningState) {
762  case Menus.TransferState.Queued:
763  return i18n.tr("In queue…");
764  case Menus.TransferState.Hashing:
765  case Menus.TransferState.Processing:
766  case Menus.TransferState.Running:
767  return timeRemaining === undefined ? i18n.tr("Downloading") : timeRemaining;
768  case Menus.TransferState.Paused:
769  return i18n.tr("Paused, tap to resume");
770  case Menus.TransferState.Canceled:
771  return i18n.tr("Canceled");
772  case Menus.TransferState.Finished:
773  return i18n.tr("Finished");
774  case Menus.TransferState.Error:
775  return i18n.tr("Failed, tap to retry");
776  }
777  return "";
778  }
779 
780  onMenuModelChanged: {
781  loadAttributes();
782  }
783  onMenuIndexChanged: {
784  loadAttributes();
785  }
786  onTriggered: {
787  actionGroup.activateAction.activate(uid);
788  }
789  onItemRemoved: {
790  actionGroup.cancelAction.activate(uid);
791  }
792 
793  function loadAttributes() {
794  if (!menuModel || menuIndex == -1) return;
795  menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-uid': 'string'});
796  }
797  }
798  }
799 
800  Component {
801  id: buttonSectionMenu;
802 
803  Menus.StandardMenu {
804  objectName: "buttonSectionMenu"
805  property QtObject menuData: null
806  property var menuModel: menuFactory.menuModel
807  property int menuIndex: -1
808  property var extendedData: menuData && menuData.ext || undefined
809 
810  iconSource: menuData && menuData.icon || ""
811  enabled: menuData && menuData.sensitive || false
812  highlightWhenPressed: false
813  text: menuData && menuData.label || ""
814  foregroundColor: Theme.palette.normal.backgroundText
815 
816  onMenuModelChanged: {
817  loadAttributes();
818  }
819  onMenuIndexChanged: {
820  loadAttributes();
821  }
822  function loadAttributes() {
823  if (!menuModel || menuIndex == -1) return;
824  menuModel.loadExtendedAttributes(menuIndex, {'x-canonical-extra-label': 'string'});
825  }
826 
827  component: Component {
828  Button {
829  objectName: "buttonSectionMenuControl"
830  text: getExtendedProperty(extendedData, "xCanonicalExtraLabel", "")
831 
832  onClicked: {
833  menuModel.activate(menuIndex);
834  }
835  }
836  }
837  }
838  }
839 
840  function load(modelData, context) {
841  if (modelData.type !== undefined && modelData.type !== "") {
842  var component = undefined;
843 
844  var contextComponents = _map[context];
845  if (contextComponents !== undefined) {
846  component = contextComponents[modelData.type];
847  }
848 
849  if (component === undefined) {
850  component = _map["default"][modelData.type];
851  }
852  if (component !== undefined) {
853  return component;
854  }
855  console.debug("Don't know how to make " + modelData.type + " for " + context);
856  }
857  if (modelData.isCheck || modelData.isRadio) {
858  return checkableMenu;
859  }
860  if (modelData.isSeparator) {
861  return separatorMenu;
862  }
863  return standardMenu;
864  }
865 }