1
/****************************************************************************
3
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4
** Copyright (C) 2014 Canonical Ltda
5
** All rights reserved.
6
** Contact: Nokia Corporation (qt-info@nokia.com)
8
** This file is part of the Qt Components project.
10
** $QT_BEGIN_LICENSE:BSD$
11
** You may use this file under the terms of the BSD license as follows:
13
** "Redistribution and use in source and binary forms, with or without
14
** modification, are permitted provided that the following conditions are
16
** * Redistributions of source code must retain the above copyright
17
** notice, this list of conditions and the following disclaimer.
18
** * Redistributions in binary form must reproduce the above copyright
19
** notice, this list of conditions and the following disclaimer in
20
** the documentation and/or other materials provided with the
22
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
23
** the names of its contributors may be used to endorse or promote
24
** products derived from this software without specific prior written
27
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
40
****************************************************************************/
44
import Ubuntu.Components 1.1
45
import "FastScroll.js" as Sections
50
property ListView listView
51
property int pinSize: units.gu(2)
53
readonly property var letters: ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "#"]
54
readonly property alias fastScrolling: internal.fastScrolling
55
readonly property bool showing: (rail.opacity !== 0.0)
59
if (listView && listView.model) {
60
internal.initDirtyObserver();
61
} else if (listView) {
62
listView.modelChanged.connect(function() {
64
internal.initDirtyObserver();
73
color: Theme.palette.normal.overlay
77
opacity: internal.fastScrolling ? 1.0 : 0.0
78
x: -cursor.width - units.gu(3)
80
if (internal.currentItem) {
81
var itemCenterY = rail.y + internal.currentItem.y + (internal.currentItem.height / 2)
82
return (itemCenterY - (magnified.height / 2))
90
horizontalAlignment: Text.AlignHCenter
91
verticalAlignment: Text.AlignVCenter
92
text: internal.desireSection
97
UbuntuNumberAnimation {}
105
property bool showLabel: false
106
property string currentSectionName: ""
108
radius: pinSize * 0.3
111
color: Theme.palette.normal.foreground
112
opacity: rail.opacity
115
if (internal.currentItem) {
116
var itemCenterY = rail.y + internal.currentItem.y + (internal.currentItem.height / 2)
117
return (itemCenterY - (cursor.height / 2))
123
enabled: !internal.fastScrolling
124
UbuntuNumberAnimation { }
131
property bool isVisible: root.enabled && (listView.moving || dragArea.pressed)
135
rightMargin: units.gu(2)
137
leftMargin: units.gu(2)
140
height: childrenRect.height
142
onIsVisibleChanged: {
151
Behavior on opacity {
152
UbuntuNumberAnimation { }
162
anchors.left: parent.left
165
verticalAlignment: Text.AlignVCenter
166
horizontalAlignment: Text.AlignHCenter
167
text: internal.fastScrolling && internal.targetSection == modelData ? "" : modelData
169
color: internal.currentItem.text === text ? Theme.palette.selected.foregroundText : Theme.palette.selected.backgroundText
170
opacity: !internal.modelDirty && Sections.contains(text) ? 1.0 : 0.5
179
onTriggered: rail.opacity = 0.0
192
visible: rail.opacity == 1.0
194
preventStealing: true
196
internal.adjustContentPosition(mouseY)
202
internal.desireSection = ""
203
internal.fastScrolling = false
206
onPositionChanged: internal.adjustContentPosition(mouseY)
214
internal.fastScrolling = true
224
Sections.initSectionData(listView);
225
internal.modelDirty = false;
235
if (internal.desireSection != internal.currentSection) {
236
var idx = Sections.getIndexFor(internal.desireSection)
238
listView.positionViewAtIndex(idx, ListView.Beginning)
247
property string currentSection: listView.currentSection
248
property string desireSection: ""
249
property string targetSection: fastScrolling ? desireSection : currentSection
251
property bool modelDirty: false
252
property bool down: true
253
property bool fastScrolling: false
254
property var currentItem: null
256
onTargetSectionChanged: moveIndicator(targetSection)
258
function initDirtyObserver() {
259
Sections.initialize(listView);
260
function dirtyObserver() {
261
if (!internal.modelDirty) {
262
internal.modelDirty = true;
263
dirtyTimer.running = true;
267
if (listView.model.countChanged)
268
listView.model.countChanged.connect(dirtyObserver);
270
if (listView.model.itemsChanged)
271
listView.model.itemsChanged.connect(dirtyObserver);
273
if (listView.model.itemsInserted)
274
listView.model.itemsInserted.connect(dirtyObserver);
276
if (listView.model.itemsMoved)
277
listView.model.itemsMoved.connect(dirtyObserver);
279
if (listView.model.itemsRemoved)
280
listView.model.itemsRemoved.connect(dirtyObserver);
283
function adjustContentPosition(mouseY) {
284
var child = rail.childAt(rail.width / 2, mouseY)
285
if (!child || child.text === "") {
288
var section = child.text
289
if (internal.desireSection !== section) {
290
internal.desireSection = section
291
moveIndicator(section)
292
timerScroll.restart()
296
function moveIndicator(section)
298
var index = root.letters.indexOf(section)
300
currentItem = sectionsRepeater.itemAt(index)