FullRepresentation.qml 26.9 KB
Newer Older
Marco Martin's avatar
Marco Martin committed
1
/*
2
    Copyright (C) 2011  Martin Gräßlin <mgraesslin@kde.org>
Marco Martin's avatar
Marco Martin committed
3
4
    Copyright (C) 2012  Gregor Taetzner <gregor@freenet.de>
    Copyright (C) 2012  Marco Martin <mart@kde.org>
David Edmundson's avatar
David Edmundson committed
5
    Copyright (C) 2013 2014 David Edmundson <davidedmundson@kde.org>
6
    Copyright 2014 Sebastian Kügler <sebas@kde.org>
Marco Martin's avatar
Marco Martin committed
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
22
import QtQuick 2.3
Marco Martin's avatar
Marco Martin committed
23
24
25
26
27
28
29
import org.kde.plasma.plasmoid 2.0
import QtQuick.Layouts 1.1
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.plasma.extras 2.0 as PlasmaExtras
import org.kde.kquickcontrolsaddons 2.0

Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
30
31
import org.kde.plasma.private.kicker 0.1 as Kicker

Marco Martin's avatar
Marco Martin committed
32
33
34
Item {
    id: root
    Layout.minimumWidth: units.gridUnit * 26
35
36
    Layout.maximumWidth: Layout.minimumWidth

37
    Layout.minimumHeight: units.gridUnit * 34
38
    Layout.maximumHeight: Layout.minimumHeight
Marco Martin's avatar
Marco Martin committed
39
40
41

    property string previousState
    property bool switchTabsOnHover: plasmoid.configuration.switchTabsOnHover
42
    property Item currentView: mainTabGroup.currentTab.decrementCurrentIndex ? mainTabGroup.currentTab : mainTabGroup.currentTab.item
43
44
    property KickoffButton firstButton: null
    property var configMenuItems
Marco Martin's avatar
Marco Martin committed
45

Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
46
47
    property QtObject globalFavorites: rootModelFavorites

Marco Martin's avatar
Marco Martin committed
48
    state: "Normal"
49
50
51
52

    onFocusChanged: {
        header.input.forceActiveFocus();
    }
Marco Martin's avatar
Marco Martin committed
53

54
    function switchToInitial() {
55
        if (firstButton != null) {
56
            root.state = "Normal";
57
58
59
60
            mainTabGroup.currentTab = firstButton.tab;
            tabBar.currentTab = firstButton;
            header.query = ""
        }
61
62
    }

63
64
65
66
67
68
69
    Kicker.DragHelper {
        id: dragHelper

        dragIconSize: units.iconSizes.medium
        onDropped: kickoff.dragSource = null
    }

Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
70
71
72
    Kicker.AppsModel {
        id: rootModel

73
74
        autoPopulate: false

Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
75
76
77
78
        appletInterface: plasmoid

        appNameFormat: plasmoid.configuration.showAppsByName ? 0 : 1
        flat: false
79
        sorted: plasmoid.configuration.alphaSort
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
80
        showSeparators: false
81
        showTopLevelItems: true
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
82

83
        favoritesModel: Kicker.KAStatsFavoritesModel {
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
84
85
86
87
88
89
90
            id: rootModelFavorites
            favorites: plasmoid.configuration.favorites

            onFavoritesChanged: {
                plasmoid.configuration.favorites = favorites;
            }
        }
91
92
93
94
95
96
97
98
99
100
101

        Component.onCompleted: {
            favoritesModel.initForClient("org.kde.plasma.kickoff.favorites.instance-" + plasmoid.id)

            if (!plasmoid.configuration.favoritesPortedToKAstats) {
                favoritesModel.portOldFavorites(plasmoid.configuration.favorites);
                plasmoid.configuration.favoritesPortedToKAstats = true;
            }

            rootModel.refresh();
        }
Kai Uwe Broulik's avatar
Kai Uwe Broulik committed
102
103
    }

104
105
106
107
108
109
    PlasmaCore.DataSource {
        id: pmSource
        engine: "powermanagement"
        connectedSources: ["PowerDevil"]
    }

110
111
112
113
114
115
116
    PlasmaCore.Svg {
        id: arrowsSvg

        imagePath: "widgets/arrows"
        size: "16x16"
    }

Marco Martin's avatar
Marco Martin committed
117
118
119
120
    Header {
        id: header
    }

Filip Fila's avatar
Filip Fila committed
121
    PlasmaCore.SvgItem {
122
123
124
125
126
        id: headerSeparator
        anchors {
            top: header.top
            horizontalCenter: header.horizontalCenter
        }
Filip Fila's avatar
Filip Fila committed
127
128
129
130
131
132
133
        height: headerSeparatorLine.elementSize("horizontal-line").height
        width: root.width - 2 * units.gridUnit
        elementId: "horizontal-line"
        svg: PlasmaCore.Svg {
            id: headerSeparatorLine
            imagePath: "widgets/line"
        }
134
135
    }

136
    Item {
137
        id: mainArea
138
        anchors.topMargin: mainTabGroup.state == "top" ? units.smallSpacing : 0
139

140
141
        PlasmaComponents.TabGroup {
            id: mainTabGroup
Marco Martin's avatar
Marco Martin committed
142
            currentTab: favoritesPage
143

144
145
146
            anchors {
                fill: parent
            }
147

148
149
150
            //pages
            FavoritesView {
                id: favoritesPage
151
            }
152
153
154
155
156
157
158
159
            PlasmaExtras.ConditionalLoader {
                id: applicationsPage
                when: mainTabGroup.currentTab == applicationsPage
                source: Qt.resolvedUrl("ApplicationsView.qml")
            }
            PlasmaExtras.ConditionalLoader {
                id: systemPage
                when: mainTabGroup.currentTab == systemPage
160
                source: Qt.resolvedUrl("ComputerView.qml")
161
162
163
164
165
166
            }
            PlasmaExtras.ConditionalLoader {
                id: recentlyUsedPage
                when: mainTabGroup.currentTab == recentlyUsedPage
                source: Qt.resolvedUrl("RecentlyUsedView.qml")
            }
167
168
169
170
171
            PlasmaExtras.ConditionalLoader {
                id: oftenUsedPage
                when: mainTabGroup.currentTab == oftenUsedPage
                source: Qt.resolvedUrl("OftenUsedView.qml")
            }
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
            PlasmaExtras.ConditionalLoader {
                id: leavePage
                when: mainTabGroup.currentTab == leavePage
                source: Qt.resolvedUrl("LeaveView.qml")
            }
            PlasmaExtras.ConditionalLoader {
                id: searchPage
                when: root.state == "Search"
                //when: mainTabGroup.currentTab == searchPage || root.state == "Search"
                source: Qt.resolvedUrl("SearchView.qml")
            }

            state: {
                switch (plasmoid.location) {
                case PlasmaCore.Types.LeftEdge:
Marco Martin's avatar
Marco Martin committed
187
                    return LayoutMirroring.enabled ? "right" : "left";
188
189
190
                case PlasmaCore.Types.TopEdge:
                    return "top";
                case PlasmaCore.Types.RightEdge:
Marco Martin's avatar
Marco Martin committed
191
                    return LayoutMirroring.enabled ? "left" : "right";
192
193
194
                case PlasmaCore.Types.BottomEdge:
                default:
                    return "bottom";
195
                }
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
            }
            states: [
                State {
                    name: "left"
                    AnchorChanges {
                        target: header
                        anchors {
                            left: root.left
                            top: undefined
                            right: root.right
                            bottom: root.bottom
                        }
                    }
                    PropertyChanges {
                        target: header
                        width: header.implicitWidth
                    }
                    AnchorChanges {
                        target: mainArea
                        anchors {
                            left: tabBar.right
                            top: root.top
                            right: root.right
                            bottom: header.top
                        }
221
                    }
222
223
224
225
                    PropertyChanges {
                        target: tabBar
                        width: (tabBar.opacity == 0) ? 0 : units.gridUnit * 5
                    }
226
227
228
229
230
231
232
233
                    AnchorChanges {
                        target: tabBar
                        anchors {
                            left: root.left
                            top: root.top
                            right: undefined
                            bottom: header.top
                        }
234
                    }
235
236
                    PropertyChanges {
                        target:tabBarSeparator
Filip Fila's avatar
Filip Fila committed
237
238
                        width: tabBarSeparatorLine.elementSize("vertical-line").width
                        elementId: "vertical-line"
239
240
241
242
243
244
                    }
                    AnchorChanges {
                        target: tabBarSeparator
                        anchors {
                            left: tabBar.right
                            top: tabBar.top
245
                            bottom:tabBar.bottom
246
247
                        }
                    }
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
                },
                State {
                    name: "top"
                    AnchorChanges {
                        target: header
                        anchors {
                            left: root.left
                            top: undefined
                            right: root.right
                            bottom: root.bottom
                        }
                    }
                    PropertyChanges {
                        target: header
                        height: header.implicitHeight
263
                    }
264
265
266
267
268
269
270
271
                    AnchorChanges {
                        target: mainArea
                        anchors {
                            left: root.left
                            top: tabBar.bottom
                            right: root.right
                            bottom: header.top
                        }
272
                    }
273
274
275
276
                    PropertyChanges {
                        target: tabBar
                        height: (tabBar.opacity == 0) ? 0 : units.gridUnit * 5
                    }
277
278
279
280
281
282
283
284
                    AnchorChanges {
                        target: tabBar
                        anchors {
                            left: root.left
                            top: root.top
                            right: root.right
                            bottom: undefined
                        }
285
                    }
286
287
                    PropertyChanges {
                        target:tabBarSeparator
Filip Fila's avatar
Filip Fila committed
288
289
                        height: tabBarSeparatorLine.elementSize("horizontal-line").height
                        elementId: "horizontal-line"
290
291
292
293
                    }
                    AnchorChanges {
                        target: tabBarSeparator
                        anchors {
294
295
                            left: tabBar.left
                            right: tabBar.right
296
297
298
                            top: tabBar.bottom
                        }
                    }
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
                },
                State {
                    name: "right"
                    AnchorChanges {
                        target: header
                        anchors {
                            left: root.left
                            top: undefined
                            right: root.right
                            bottom: root.bottom
                        }
                    }
                    PropertyChanges {
                        target: header
                        width: header.implicitWidth
314
                    }
315
316
317
318
319
320
321
322
                    AnchorChanges {
                        target: mainArea
                        anchors {
                            left: root.left
                            top: root.top
                            right: tabBar.left
                            bottom: header.top
                        }
323
                    }
324
325
326
327
                    PropertyChanges {
                        target: tabBar
                        width: (tabBar.opacity == 0) ? 0 : units.gridUnit * 5
                    }
328
329
330
331
332
333
334
335
                    AnchorChanges {
                        target: tabBar
                        anchors {
                            left: undefined
                            top: root.top
                            right: root.right
                            bottom: header.top
                        }
336
                    }
337
338
                    PropertyChanges {
                        target:tabBarSeparator
Filip Fila's avatar
Filip Fila committed
339
340
                        width: tabBarSeparatorLine.elementSize("vertical-line").width
                        elementId: "vertical-line"
341
342
343
344
345
                    }
                    AnchorChanges {
                        target: tabBarSeparator
                        anchors {
                            right: tabBar.left
346
                            top: tabBar.top
347
348
349
                            bottom: tabBar.bottom
                        }
                    }
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
                },
                State {
                    name: "bottom"
                    AnchorChanges {
                        target: header
                        anchors {
                            left: root.left
                            top: root.top
                            right: root.right
                            bottom: undefined
                        }
                    }
                    PropertyChanges {
                        target: header
                        height: header.implicitHeight
365
                    }
366
367
368
369
370
371
372
                    AnchorChanges {
                        target: headerSeparator
                        anchors {
                            top: undefined
                            bottom: header.bottom
                        }
                    }
373
374
375
376
377
378
379
380
                    AnchorChanges {
                        target: mainArea
                        anchors {
                            left: root.left
                            top: header.bottom
                            right: root.right
                            bottom: tabBar.top
                        }
381
                    }
382
383
384
385
                    PropertyChanges {
                        target: tabBar
                        height: (tabBar.opacity == 0) ? 0 : units.gridUnit * 5
                    }
386
387
388
389
390
391
392
393
                    AnchorChanges {
                        target: tabBar
                        anchors {
                            left: root.left
                            top: undefined
                            right: root.right
                            bottom: root.bottom
                        }
394
                    }
395
396
                    PropertyChanges {
                        target:tabBarSeparator
Filip Fila's avatar
Filip Fila committed
397
398
                        height: tabBarSeparatorLine.elementSize("horizontal-line").height
                        elementId: "horizontal-line"
399
400
401
402
403
                    }
                    AnchorChanges {
                        target: tabBarSeparator
                        anchors {
                            bottom: tabBar.top
404
405
                            left: tabBar.left
                            right: tabBar.right
406
407
                        }
                    }
408
                }
409
410
411
            ]
        } // mainTabGroup
    }
Marco Martin's avatar
Marco Martin committed
412
413
414
415

    PlasmaComponents.TabBar {
        id: tabBar

416
417
        property int count: 5 // updated in createButtons()

418
419
420
421
422
423
424
425
        Behavior on width {
            NumberAnimation { duration: units.longDuration; easing.type: Easing.InQuad; }
            enabled: plasmoid.expanded
        }
        Behavior on height {
            NumberAnimation { duration: units.longDuration; easing.type: Easing.InQuad; }
            enabled: plasmoid.expanded
        }
Marco Martin's avatar
Marco Martin committed
426
427
428
429
430
431
432
433
434
435
436
437
438
439

        tabPosition: {
            switch (plasmoid.location) {
            case PlasmaCore.Types.TopEdge:
                return Qt.TopEdge;
            case PlasmaCore.Types.LeftEdge:
                return Qt.LeftEdge;
            case PlasmaCore.Types.RightEdge:
                return Qt.RightEdge;
            default:
                return Qt.BottomEdge;
            }
        }

440
        onCurrentTabChanged: header.input.forceActiveFocus();
Marco Martin's avatar
Marco Martin committed
441

442
443
444
        Connections {
            target: plasmoid
            onExpandedChanged: {
445
446
447
                if(menuItemsChanged()) {
                    createButtons();
                }
448
                if (!expanded) {
449
                    switchToInitial();
450
451
452
                }
            }
        }
Marco Martin's avatar
Marco Martin committed
453
454
    } // tabBar

Filip Fila's avatar
Filip Fila committed
455
    PlasmaCore.SvgItem {
456
        id: tabBarSeparator
Filip Fila's avatar
Filip Fila committed
457
458
459
460
        svg: PlasmaCore.Svg {
            id: tabBarSeparatorLine
            imagePath: "widgets/line"
        }
461
462
    }

463
464
465
466
467
    MouseArea {
        anchors.fill: tabBar

        property var oldPos: null

468
        enabled: root.state !== "Search"
469
470
471
472
473
474
475
476
477
478
479
        hoverEnabled: root.switchTabsOnHover

        onExited: {
            // Reset so we switch immediately when MouseArea is entered
            // freshly, e.g. from the panel.
            oldPos = null;

            clickTimer.stop();
        }

        onPositionChanged: {
480
481
482
483
484
485
            // Reject multiple events with the same coordinates that QQuickWindow
            // synthesizes.
            if (oldPos === Qt.point(mouse.x, mouse.y)) {
                return;
            }

486
487
            var button = tabBar.layout.childAt(mouse.x, mouse.y);

Laurent Montel's avatar
Laurent Montel committed
488
            if (!button || button.objectName !== "KickoffButton") {
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
                clickTimer.stop();

                return;
            }

            // Switch immediately when MouseArea was freshly entered, e.g.
            // from the panel.
            if (oldPos === null) {
                oldPos = Qt.point(mouse.x, mouse.y);

                clickTimer.stop();
                button.clicked();

                return;
            }

            var dx  = (mouse.x - oldPos.x);
            var dy  = (mouse.y - oldPos.y);

            // Check Manhattan length against drag distance to get a decent
            // pointer motion vector.
            if ((Math.abs(dx) + Math.abs(dy)) > Qt.styleHints.startDragDistance) {
Laurent Montel's avatar
Laurent Montel committed
511
                if (tabBar.currentTab !== button) {
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
                    var tabBarPos = mapToItem(tabBar, oldPos.x, oldPos.y);
                    oldPos = Qt.point(mouse.x, mouse.y);

                    var angleMouseMove = Math.atan2(dy, dx) * 180 / Math.PI;
                    var angleToCornerA = 0;
                    var angleToCornerB = 0;

                    switch (plasmoid.location) {
                        case PlasmaCore.Types.TopEdge: {
                            angleToCornerA = Math.atan2(tabBar.height - tabBarPos.y, 0 - tabBarPos.x);
                            angleToCornerB = Math.atan2(tabBar.height - tabBarPos.y, tabBar.width - tabBarPos.x);

                            break;
                        }
                        case PlasmaCore.Types.LeftEdge: {
                            angleToCornerA = Math.atan2(0 - tabBarPos.y, tabBar.width - tabBarPos.x);
                            angleToCornerB = Math.atan2(tabBar.height - tabBarPos.y, tabBar.width - tabBarPos.x);

                            break;
                        }
                        case PlasmaCore.Types.RightEdge: {
                            angleToCornerA = Math.atan2(0 - tabBarPos.y, 0 - tabBarPos.x);
                            angleToCornerB = Math.atan2(tabBar.height - tabBarPos.y, 0 - tabBarPos.x);

                            break;
                        }
                        // PlasmaCore.Types.BottomEdge
                        default: {
                            angleToCornerA = Math.atan2(0 - tabBarPos.y, 0 - tabBarPos.x);
                            angleToCornerB = Math.atan2(0 - tabBarPos.y, tabBar.width - tabBarPos.x);
                        }
                    }

                    // Degrees are nicer to debug than radians.
                    angleToCornerA = angleToCornerA * 180 / Math.PI;
                    angleToCornerB = angleToCornerB * 180 / Math.PI;

                    var lower = Math.min(angleToCornerA, angleToCornerB);
                    var upper = Math.max(angleToCornerA, angleToCornerB);

                    // If the motion vector is outside the angle range from oldPos to the
                    // relevant tab bar corners, switch immediately. Otherwise start the
Yuri Chornoivan's avatar
Yuri Chornoivan committed
554
                    // timer, which gets aborted should the pointer exit the tab bar
555
556
557
558
                    // early.
                    var inRange = (lower < angleMouseMove == angleMouseMove < upper);

                    // Mirror-flip.
Laurent Montel's avatar
Laurent Montel committed
559
                    if (plasmoid.location === PlasmaCore.Types.RightEdge ? inRange : !inRange) {
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
                        clickTimer.stop();
                        button.clicked();

                        return;
                    } else {
                        clickTimer.pendingButton = button;
                        clickTimer.start();
                    }
                } else {
                    oldPos = Qt.point(mouse.x, mouse.y);
                }
            }
        }

        onClicked: {
            clickTimer.stop();

            var button = tabBar.layout.childAt(mouse.x, mouse.y);

Laurent Montel's avatar
Laurent Montel committed
579
            if (!button || button.objectName !== "KickoffButton") {
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
                return;
            }

            button.clicked();
        }

        Timer {
            id: clickTimer

            property Item pendingButton: null

            interval: 250

            onTriggered: {
                if (pendingButton) {
                    pendingButton.clicked();
                }
            }
        }
    }

Marco Martin's avatar
Marco Martin committed
601
602
603
604
    Keys.forwardTo: [tabBar.layout]

    Keys.onPressed: {

605
        if (mainTabGroup.currentTab == applicationsPage) {
Laurent Montel's avatar
Laurent Montel committed
606
            if (event.key !== Qt.Key_Tab) {
Marco Martin's avatar
Marco Martin committed
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
                root.state = "Applications";
            }
        }

        switch(event.key) {
            case Qt.Key_Up: {
                currentView.decrementCurrentIndex();
                event.accepted = true;
                break;
            }
            case Qt.Key_Down: {
                currentView.incrementCurrentIndex();
                event.accepted = true;
                break;
            }
            case Qt.Key_Left: {
623
                if (header.input.focus && header.state == "query") {
Marco Martin's avatar
Marco Martin committed
624
625
626
                    break;
                }
                if (!currentView.deactivateCurrentIndex()) {
627
                    if (root.state == "Applications") {
628
629
                        mainTabGroup.currentTab = firstButton.tab;
                        tabBar.currentTab = firstButton;
630
                    }
Marco Martin's avatar
Marco Martin committed
631
632
633
634
635
636
                    root.state = "Normal"
                }
                event.accepted = true;
                break;
            }
            case Qt.Key_Right: {
637
                if (header.input.focus && header.state == "query") {
Marco Martin's avatar
Marco Martin committed
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
                    break;
                }
                currentView.activateCurrentIndex();
                event.accepted = true;
                break;
            }
            case Qt.Key_Tab: {
                root.state == "Applications" ? root.state = "Normal" : root.state = "Applications";
                event.accepted = true;
                break;
            }
            case Qt.Key_Enter:
            case Qt.Key_Return: {
                currentView.activateCurrentIndex(1);
                event.accepted = true;
                break;
            }
            case Qt.Key_Escape: {
656
                if (header.state != "query") {
Marco Martin's avatar
Marco Martin committed
657
658
                    plasmoid.expanded = false;
                } else {
659
                    header.query = "";
Marco Martin's avatar
Marco Martin committed
660
661
662
663
                }
                event.accepted = true;
                break;
            }
664
665
666
667
668
            case Qt.Key_Menu: {
                currentView.openContextMenu();
                event.accepted = true;
                break;
            }
669
670
            default:
                if (!header.input.focus) {
Marco Martin's avatar
Marco Martin committed
671
672
673
674
675
676
677
678
679
680
681
682
                    header.input.forceActiveFocus();
                }
        }
    }

    states: [
        State {
            name: "Normal"
            PropertyChanges {
                target: root
                Keys.forwardTo: [tabBar.layout]
            }
683
684
            PropertyChanges {
                target: tabBar
Marco Martin's avatar
Marco Martin committed
685
686
                //Set the opacity and NOT the visibility, as visibility is recursive
                //and this binding would be executed also on popup show/hide
687
                //as recommended by the docs: https://doc.qt.io/qt-5/qml-qtquick-item.html#visible-prop
Marco Martin's avatar
Marco Martin committed
688
689
690
                //plus, it triggers https://bugreports.qt.io/browse/QTBUG-66907
                //in which a mousearea may think it's under the mouse while it isn't
                opacity: tabBar.count > 1 ? 1 : 0
691
            }
Marco Martin's avatar
Marco Martin committed
692
693
694
695
696
697
698
        },
        State {
            name: "Applications"
            PropertyChanges {
                target: root
                Keys.forwardTo: [root]
            }
699
700
            PropertyChanges {
                target: tabBar
Marco Martin's avatar
Marco Martin committed
701
                opacity: tabBar.count > 1 ? 1 : 0
702
            }
Marco Martin's avatar
Marco Martin committed
703
704
705
706
707
        },
        State {
            name: "Search"
            PropertyChanges {
                target: tabBar
Marco Martin's avatar
Marco Martin committed
708
                opacity: 0
Marco Martin's avatar
Marco Martin committed
709
710
            }
            PropertyChanges {
711
                target: mainTabGroup
Marco Martin's avatar
Marco Martin committed
712
713
                currentTab: searchPage
            }
714
715
716
717
            PropertyChanges {
                target: root
                Keys.forwardTo: [root]
            }
Marco Martin's avatar
Marco Martin committed
718
719
        }
    ] // states
720
721
722
723

    function getButtonDefinition(name) {
        switch(name) {
        case "bookmark":
724
            return {id: "bookmarkButton", tab: favoritesPage, iconSource: "bookmarks", text: i18n("Favorites")};
725
        case "application":
726
            return {id: "applicationButton", tab: applicationsPage, iconSource: "applications-other", text: i18n("Applications")};
727
        case "computer":
728
            return {id: "computerButton", tab: systemPage, iconSource: pmSource.data["PowerDevil"] && pmSource.data["PowerDevil"]["Is Lid Present"] ? "computer-laptop" : "computer", text: i18n("Computer")};
729
        case "used":
730
            return {id: "usedButton", tab: recentlyUsedPage, iconSource: "view-history", text: i18n("History")};
731
732
        case "oftenUsed":
            return {id: "usedButton", tab: oftenUsedPage, iconSource: "office-chart-pie", text: i18n("Often Used")};
733
        case "leave":
734
            return {id: "leaveButton", tab: leavePage, iconSource: "system-log-out", text: i18n("Leave")};
735
736
737
        }
    }

738
739
740
741
742
743
    Component {
        id: kickoffButton
        KickoffButton {}
    }


744
745
746
747
748
749
750
751
    Component.onCompleted: {
        createButtons();
    }

    function getEnabled(configuration) {
        var res = [];
        for(var i = 0; i < configuration.length; i++) {
            var confItemName = configuration[i].substring(0, configuration[i].indexOf(":"));
Laurent Montel's avatar
Laurent Montel committed
752
            var confItemEnabled = configuration[i].substring(configuration[i].length-1) === "t";
753
754
755
756
757
758
759
760
761
762
763
            if(confItemEnabled) {
                res.push(confItemName);
            }
        }

        return res;
    }

    function createButtons() {
        configMenuItems = plasmoid.configuration.menuItems;
        var menuItems = getEnabled(plasmoid.configuration.menuItems);
764
        tabBar.count = menuItems.length
765
766
767

        // remove old menu items
        for(var i = tabBar.layout.children.length -1; i >= 0; i--)  {
Laurent Montel's avatar
Laurent Montel committed
768
            if(tabBar.layout.children[i].objectName === "KickoffButton") {
769
770
771
772
773
                tabBar.layout.children[i].destroy();
            }
        }

        for (var i = 0; i < menuItems.length; i++) {
774
775
             var props = getButtonDefinition(menuItems[i]);
             var button = kickoffButton.createObject(tabBar.layout, props);
Laurent Montel's avatar
Laurent Montel committed
776
             if(i === 0) {
777
778
779
780
781
782
783
784
                 firstButton = button;
                 switchToInitial();
             }
        }

    }

    function menuItemsChanged() {
Laurent Montel's avatar
Laurent Montel committed
785
        if(configMenuItems.length !== plasmoid.configuration.menuItems.length) {
786
787
788
789
            return true;
        }

        for(var i = 0; i < configMenuItems.length; i++) {
Laurent Montel's avatar
Laurent Montel committed
790
            if(configMenuItems[i] !== plasmoid.configuration.menuItems[i]) {
791
792
793
794
795
                return true;
            }
        }
        return false;
    }
Marco Martin's avatar
Marco Martin committed
796
}