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