on xenial help sign in
Need to expand capability of QSortFilterProxyModelQML to explicitly emit signal on any row manipulations. With this can fix much behaviours in shell. The main & side stage focused apps are now working
d835e2aGerry Boland
Components/ApplicationManagerWrapper.qml+26−33
@@ -16,15 +16,14 @@
16
16
17import QtQuick 2.0
17import QtQuick 2.0
18import Unity.Application 0.1
18import Unity.Application 0.1
19−import Utils 0.1
20
19
21Item {
20Item {
22 id: applicationManager
21 id: applicationManager
23
22
24− property var mainStageApplications: mainStageModel
23+ property alias mainStageApplications: mainStageModel
25− property var sideStageApplications: sideStageModel
24+ property alias sideStageApplications: sideStageModel
26− property var mainStageFocusedApplication: null
25+ property alias mainStageFocusedApplication: mainStageModel.focusedApplication
27− property var sideStageFocusedApplication: null
26+ property alias sideStageFocusedApplication: sideStageModel.focusedApplication
28 property bool sideStageEnabled: true
27 property bool sideStageEnabled: true
29 signal focusRequested(string desktopFile)
28 signal focusRequested(string desktopFile)
30 property bool keyboardVisible: ApplicationManager.keyboardVisible
29 property bool keyboardVisible: ApplicationManager.keyboardVisible
@@ -32,39 +31,21 @@ Item {
32
31
33 property bool fake: ApplicationManager.fake ? ApplicationManager.fake : false
32 property bool fake: ApplicationManager.fake ? ApplicationManager.fake : false
34
33
35− SortFilterProxyModel {
34+ ApplicationsModelStageFiltered {
36 id: mainStageModel
35 id: mainStageModel
37− model: ApplicationManager
38− dynamicSortFilter: true
39− filterRole: ApplicationManager.RoleStage
40− filterRegExp: RegExp(ApplicationInfo.MainStage)
36+ stage: ApplicationInfo.MainStage
41−
42− onCountChanged: { print("MODEL Main:", count, ApplicationManager.RoleStage, ApplicationManager.RoleFocused)
43− mainStageFocusedApplication = ApplicationManager.get(mainStageModel.findFirst(ApplicationManager.RoleFocused, true));
44− print("MS", mainStageFocusedApplication)
45− }
46− onLayoutChanged: print("LAYOUT")
47− onDataChanged: print("DATA")
48 }
37 }
49
38
50− SortFilterProxyModel {
39+ ApplicationsModelStageFiltered {
51 id: sideStageModel
40 id: sideStageModel
52− model: ApplicationManager
53− dynamicSortFilter: true
54− filterRole: ApplicationManager.RoleStage
55− filterRegExp: RegExp(ApplicationInfo.SideStage)
41+ stage: ApplicationInfo.SideStage
56−
57− onDataChanged: { print("MODEL Side", count)
58− sideStageFocusedApplication = ApplicationManager.get(sideStageModel.findFirst(ApplicationManager.RoleFocused, true));
59− print("SS", sideStageFocusedApplication)
60− }
61 }
42 }
62
43
63 function activateApplication(desktopFile, argument) {
44 function activateApplication(desktopFile, argument) {
64 var appId;
45 var appId;
65
46
66 // HACK: might be called with appId, but mostly with desktopFile
47 // HACK: might be called with appId, but mostly with desktopFile
67− if (desktopFile.indexOf(".desktop") = -1) {
48+ if (desktopFile.indexOf(".desktop") >= 0) {
68 appId = desktopFileToAppId(desktopFile);
49 appId = desktopFileToAppId(desktopFile);
69 } else {
50 } else {
70 appId = desktopFile;
51 appId = desktopFile;
@@ -97,7 +78,7 @@ Item {
97 ApplicationManager.stopProcess(appId);
78 ApplicationManager.stopProcess(appId);
98 }
79 }
99
80
100− function focusApplication(application) {
81+ function focusApplication(application) {print("focusApplication", application.appId)
101 if (application == null || application == undefined) {
82 if (application == null || application == undefined) {
102 return;
83 return;
103 }
84 }
@@ -109,13 +90,25 @@ Item {
109 ApplicationManager.unfocusCurrentApplication();
90 ApplicationManager.unfocusCurrentApplication();
110 }
91 }
111
92
112− function moveRunningApplicationStackPosition(from, to, stage) { //FIXME: stage unused!
93+ function moveRunningApplicationStackPosition(from, to, stage) { print("moveRunningApplicationStackPosition", from, to, stage)
113− if (from !== to && from >= 0 && to >= 0) ApplicationManager.move(from, to);
94+ if (from == to || from < 0 || to < 0) return;
95+
96+ if (stage == ApplicationInfo.SideStage) {
97+ sideStageModel.move(from, to);
98+ } else {
99+ mainStageModel.move(from, to);
100+ }
114 }
101 }
115
102
116 function getApplicationFromDesktopFile(desktopFile, stage) {
103 function getApplicationFromDesktopFile(desktopFile, stage) {
117− var foundSideStageApp, foundMainStageApp;
104+ var appId;
105+
106+ // HACK: might be called with appId, but mostly with desktopFile
107+ if (desktopFile.indexOf(".desktop") >= 0) {
118− var appId = desktopFileToAppId(desktopFile);
108+ appId = desktopFileToAppId(desktopFile);
109+ } else {
110+ appId = desktopFile;
111+ }
119
112
120 for (var i = 0, len = ApplicationManager.count; i < len; i++ ) {
113 for (var i = 0, len = ApplicationManager.count; i < len; i++ ) {
121 var app = ApplicationManager.get(i);
114 var app = ApplicationManager.get(i);
Components/ApplicationScreenshot.qml+1−1
@@ -25,7 +25,7 @@ Item {
25 property bool withBackground: false
25 property bool withBackground: false
26 property bool ready: applicationImage.ready || withBackground
26 property bool ready: applicationImage.ready || withBackground
27
27
28− function setApplication(application) {
28+ function setApplication(application) { print("SET APP", application, (application) ? application.appId : "")
29 applicationScreenshot.application = application
29 applicationScreenshot.application = application
30 }
30 }
31
31
Components/ApplicationsModelStageFiltered.qmlnew file+54
@@ -0,0 +1,54 @@
1+/*
2+ * Copyright (C) 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 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 General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import Utils 0.1
19+import Unity.Application 0.1
20+
21+SortFilterProxyModel {
22+ id: root
23+ property int stage
24+ property variant focusedApplication: null
25+
26+ function get(index) {
27+ print("GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG get", index)
28+ return ApplicationManager.get(mapRowToSource(index));
29+ }
30+
31+ function move(from, to) {
32+ var realFrom = mapRowToSource(from);
33+ if (realFrom == -1) {
34+ console.log("ERROR; invalid from=" + from + " index in move operation");
35+ return;
36+ }
37+ var realTo = mapRowToSource(to);
38+ if (realTo == -1) {
39+ // assuming wanting to move to end of list
40+ realTo = ApplicationManager.count;
41+ }
42+ ApplicationManager.move(realFrom, realTo);
43+ }
44+
45+ model: ApplicationManager
46+ dynamicSortFilter: true
47+ filterRole: ApplicationManager.RoleStage
48+ filterRegExp: RegExp(stage)
49+
50+ onLayoutChanged: {
51+ focusedApplication = get(0);
52+ print("LAYOUT CHANGED", focusedApplication.appId)
53+ }
54+}
Components/Stage.qml+3−3
@@ -142,7 +142,7 @@ Showable {
142 oldApplicationScreenshot.visible = false;
142 oldApplicationScreenshot.visible = false;
143 }
143 }
144
144
145− function __focusApplication(application) {
145+ function __focusApplication(application) { print("__focusApplication", application)
146 if (!application) return
146 if (!application) return
147 if (shouldUseScreenshots) {
147 if (shouldUseScreenshots) {
148 stage.__focusApplicationUsingScreenshots(application);
148 stage.__focusApplicationUsingScreenshots(application);
@@ -267,7 +267,7 @@ Showable {
267 SequentialAnimation {
267 SequentialAnimation {
268 id: showStartingApplicationAnimation
268 id: showStartingApplicationAnimation
269
269
270− function prepare(newApplication) {
270+ function prepare(newApplication) { print("showStartingApplicationAnimation::prepare", newApplication)
271 var oldApplication = stage.focusedApplication;
271 var oldApplication = stage.focusedApplication;
272 newApplicationScreenshot.setApplication(newApplication);
272 newApplicationScreenshot.setApplication(newApplication);
273 newApplicationScreenshot.updateFromCache();
273 newApplicationScreenshot.updateFromCache();
@@ -336,7 +336,7 @@ Showable {
336 SequentialAnimation {
336 SequentialAnimation {
337 id: switchToApplicationAnimation
337 id: switchToApplicationAnimation
338
338
339− function prepare(newApplication) {
339+ function prepare(newApplication) { print("switchToApplicationAnimation::prepare", newApplication)
340 var oldApplication = stage.focusedApplication;
340 var oldApplication = stage.focusedApplication;
341 newApplicationScreenshot.setApplication(newApplication);
341 newApplicationScreenshot.setApplication(newApplication);
342 newApplicationScreenshot.updateFromCache();
342 newApplicationScreenshot.updateFromCache();
Dash/Apps/RunningApplicationTile.qml+1−1
@@ -76,7 +76,7 @@ AbstractButton {
76
76
77 ApplicationImage {
77 ApplicationImage {
78 id: applicationImage
78 id: applicationImage
79− source: application
79+ source: ApplicationManager.findApplication((application) ? application.appId : "")
80 width: shapedApplicationImage.width
80 width: shapedApplicationImage.width
81 height: shapedApplicationImage.height
81 height: shapedApplicationImage.height
82 fillMode: ApplicationImage.PreserveAspectCrop
82 fillMode: ApplicationImage.PreserveAspectCrop
Dash/Apps/RunningApplicationsGrid.qml+4−4
@@ -52,22 +52,22 @@ ResponsiveFlowView {
52
52
53 RunningApplicationTile {
53 RunningApplicationTile {
54 id: runningAppTile
54 id: runningAppTile
55− objectName: "runningAppTile " + model.application.name
55+ objectName: "runningAppTile " + model.name
56 anchors {
56 anchors {
57 top: parent.top
57 top: parent.top
58 horizontalCenter: parent.horizontalCenter
58 horizontalCenter: parent.horizontalCenter
59 }
59 }
60− application: model.application
60+ application: model
61 onRequestedActivationMode: { root.terminationModeEnabled = false }
61 onRequestedActivationMode: { root.terminationModeEnabled = false }
62 onRequestedTerminationMode: {
62 onRequestedTerminationMode: {
63 if (canEnableTerminationMode)
63 if (canEnableTerminationMode)
64 root.terminationModeEnabled = true
64 root.terminationModeEnabled = true
65 }
65 }
66 onRequestedApplicationTermination: {
66 onRequestedApplicationTermination: {
67− shell.applicationManager.stopProcess(application)
67+ shell.applicationManager.stopApplication(model.appId)
68 }
68 }
69 onRequestedApplicationActivation: {
69 onRequestedApplicationActivation: {
70− shell.activateApplication(application.desktopFile)
70+ shell.activateApplication(model.appId)
71 }
71 }
72
72
73 terminationModeEnabled: root.terminationModeEnabled
73 terminationModeEnabled: root.terminationModeEnabled
plugins/Utils/qsortfilterproxymodelqml.cpp+18
@@ -29,6 +29,17 @@ QSortFilterProxyModelQML::QSortFilterProxyModelQML(QObject *parent)
29 connect(this, SIGNAL(rowsRemoved(QModelIndex,int,int)), SIGNAL(countChanged()));
29 connect(this, SIGNAL(rowsRemoved(QModelIndex,int,int)), SIGNAL(countChanged()));
30}
30}
31
31
32+/*
33+ * Enter row index of filtered/sorted model, returns row index of source model
34+ */
35+int QSortFilterProxyModelQML::mapRowToSource(int row)
36+{
37+ if (sourceModel() == NULL)
38+ return -1;
39+
40+ return QSortFilterProxyModel::mapToSource(index(row, 0)).row();
41+}
42+
32QHash<int, QByteArray> QSortFilterProxyModelQML::roleNames() const
43QHash<int, QByteArray> QSortFilterProxyModelQML::roleNames() const
33{
44{
34 return sourceModel() ? sourceModel()->roleNames() : QHash<int, QByteArray>();
45 return sourceModel() ? sourceModel()->roleNames() : QHash<int, QByteArray>();
@@ -51,7 +62,14 @@ QSortFilterProxyModelQML::setModel(QAbstractItemModel *itemModel)
51 connect(itemModel, SIGNAL(modelReset()), SIGNAL(totalCountChanged()));
62 connect(itemModel, SIGNAL(modelReset()), SIGNAL(totalCountChanged()));
52 connect(itemModel, SIGNAL(rowsInserted(QModelIndex,int,int)), SIGNAL(totalCountChanged()));
63 connect(itemModel, SIGNAL(rowsInserted(QModelIndex,int,int)), SIGNAL(totalCountChanged()));
53 connect(itemModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), SIGNAL(totalCountChanged()));
64 connect(itemModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), SIGNAL(totalCountChanged()));
65+
66+ connect(itemModel, SIGNAL(modelReset()), SIGNAL(layoutChanged()));
67+ connect(itemModel, SIGNAL(rowsInserted(QModelIndex,int,int)), SIGNAL(layoutChanged()));
68+ connect(itemModel, SIGNAL(rowsRemoved(QModelIndex,int,int)), SIGNAL(layoutChanged()));
69+ connect(itemModel, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), SIGNAL(layoutChanged()));
70+
54 Q_EMIT totalCountChanged();
71 Q_EMIT totalCountChanged();
72+ Q_EMIT layoutChanged();
55 Q_EMIT modelChanged();
73 Q_EMIT modelChanged();
56 }
74 }
57}
75}
plugins/Utils/qsortfilterproxymodelqml.h+2
@@ -34,6 +34,7 @@ public:
34 Q_INVOKABLE QVariant data(int row, int role);
34 Q_INVOKABLE QVariant data(int row, int role);
35 Q_INVOKABLE int count();
35 Q_INVOKABLE int count();
36 Q_INVOKABLE int findFirst(int role, const QVariant& value) const;
36 Q_INVOKABLE int findFirst(int role, const QVariant& value) const;
37+ Q_INVOKABLE int mapRowToSource(int row);
37 virtual bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
38 virtual bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
38
39
39 /* getters */
40 /* getters */
@@ -50,6 +51,7 @@ Q_SIGNALS:
50 void countChanged();
51 void countChanged();
51 void invertMatchChanged(bool);
52 void invertMatchChanged(bool);
52 void modelChanged();
53 void modelChanged();
54+ void layoutChanged();
53
55
54private:
56private:
55 bool m_invertMatch;
57 bool m_invertMatch;