Unity 8
IndicatorPage.qml
1 /*
2  * Copyright 2013-2014 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 
17 import QtQuick 2.4
18 import Ubuntu.Components 1.3 as Components
19 import Unity.Indicators 0.1 as Indicators
20 import "Indicators"
21 
22 IndicatorBase {
23  id: main
24 
25  //const
26  property string title: rootActionState.title || rootActionState.accessibleName // some indicators don't expose a title but only the accessible-desc
27  property alias highlightFollowsCurrentItem : mainMenu.highlightFollowsCurrentItem
28  readonly property alias factory: _factory
29 
30  Indicators.UnityMenuModelStack {
31  id: menuStack
32  head: main.menuModel
33 
34  property var rootMenu: null
35 
36  onTailChanged: {
37  if (!tail) {
38  rootMenu = null;
39  } else if (rootMenu != tail) {
40  if (tail.get(0, "type") === rootMenuType) {
41  rootMenu = menuStack.tail.submenu(0);
42  push(rootMenu, 0);
43  } else {
44  rootMenu = null;
45  }
46  }
47  }
48  }
49 
50  Connections {
51  target: menuStack.tail
52 
53  // fix async creation with signal from model before it's finished.
54  Component.onCompleted: update();
55  onRowsInserted: update();
56  onModelReset: update();
57 
58  function update() {
59  if (menuStack.rootMenu !== menuStack.tail && menuStack.tail.get(0, "type") === rootMenuType) {
60  menuStack.rootMenu = menuStack.tail.submenu(0);
61  menuStack.push(menuStack.rootMenu, 0);
62  }
63  }
64  }
65 
66  ListView {
67  id: mainMenu
68  objectName: "mainMenu"
69  model: menuStack.rootMenu
70 
71  anchors {
72  fill: parent
73  bottomMargin: Qt.inputMethod.visible ? (Qt.inputMethod.keyboardRectangle.height - main.anchors.bottomMargin) : 0
74 
75  Behavior on bottomMargin {
76  NumberAnimation {
77  duration: 175
78  easing.type: Easing.OutQuad
79  }
80  }
81  // TODO - does ever frame.
82  onBottomMarginChanged: {
83  mainMenu.positionViewAtIndex(mainMenu.currentIndex, ListView.End)
84  }
85  }
86 
87  // Don't load all the delegates (only max of 3 pages worth -1/0/+1)
88  cacheBuffer: Math.max(height * 3, units.gu(70))
89 
90  // Only allow flicking if the content doesn't fit on the page
91  interactive: contentHeight > height
92 
93  property int selectedIndex: -1
94  property bool blockCurrentIndexChange: false
95  // for count = 0
96  onCountChanged: {
97  if (count == 0 && selectedIndex != -1) {
98  selectedIndex = -1;
99  }
100  }
101  // for highlight following
102  onSelectedIndexChanged: {
103  if (currentIndex != selectedIndex) {
104  var blocked = blockCurrentIndexChange;
105  blockCurrentIndexChange = true;
106 
107  currentIndex = selectedIndex;
108 
109  blockCurrentIndexChange = blocked;
110  }
111  }
112  // for item addition/removal
113  onCurrentIndexChanged: {
114  if (!blockCurrentIndexChange) {
115  if (selectedIndex != -1 && selectedIndex != currentIndex) {
116  selectedIndex = currentIndex;
117  }
118  }
119  }
120 
121  Connections {
122  target: mainMenu.model ? mainMenu.model : null
123  onRowsAboutToBeRemoved: {
124  // track current item deletion.
125  if (mainMenu.selectedIndex >= first && mainMenu.selectedIndex <= last) {
126  mainMenu.selectedIndex = -1;
127  }
128  }
129  }
130 
131  delegate: Loader {
132  id: loader
133  objectName: "menuItem" + index
134  width: ListView.view.width
135  visible: status == Loader.Ready
136 
137  property int modelIndex: index
138  sourceComponent: factory.load(model, main.identifier)
139 
140  onLoaded: {
141  if (item.hasOwnProperty("selected")) {
142  item.selected = mainMenu.selectedIndex == index;
143  }
144  if (item.hasOwnProperty("menuSelected")) {
145  item.menuSelected.connect(function() { mainMenu.selectedIndex = index; });
146  }
147  if (item.hasOwnProperty("menuDeselected")) {
148  item.menuDeselected.connect(function() { mainMenu.selectedIndex = -1; });
149  }
150  if (item.hasOwnProperty("menuData")) {
151  item.menuData = Qt.binding(function() { return model; });
152  }
153  if (item.hasOwnProperty("menuIndex")) {
154  item.menuIndex = Qt.binding(function() { return modelIndex; });
155  }
156  }
157 
158  Binding {
159  target: item ? item : null
160  property: "objectName"
161  value: model.action
162  }
163 
164  // TODO: Fixes lp#1243146
165  // This is a workaround for a Qt bug. https://bugreports.qt-project.org/browse/QTBUG-34351
166  Connections {
167  target: mainMenu
168  onSelectedIndexChanged: {
169  if (loader.item && loader.item.hasOwnProperty("selected")) {
170  loader.item.selected = mainMenu.selectedIndex == index;
171  }
172  }
173  }
174  }
175  }
176 
177  MenuItemFactory {
178  id: _factory
179  rootModel: main.menuModel ? main.menuModel : null
180  menuModel: mainMenu.model ? mainMenu.model : null
181  }
182 
183  function reset()
184  {
185  mainMenu.positionViewAtBeginning();
186  }
187 }