on xenial help sign in
Support switching indicator profiles between normal and greeter versions
c243570Michael Terry
plugins/Unity/Indicators/indicator.cpp+25−8
@@ -33,23 +33,27 @@ Indicator::~Indicator()
33
33
34void Indicator::init(const QString &profile, const QString& busName, const QSettings& settings)
34void Indicator::init(const QString &profile, const QString& busName, const QSettings& settings)
35{
35{
36− setId(settings.value("Indicator Service/Name").toString());
36+ // Save all keys we care about from the QSettings object. It's annoying
37+ // that we can't just copy the object.
38+ m_settings.clear();
39+ Q_FOREACH(const QString& key, settings.allKeys()) {
40+ if (key.endsWith("/Position") || key.endsWith("/ObjectPath")) {
41+ m_settings.insert(key, settings.value(key));
42+ }
43+ }
37
44
38− QVariant pos = settings.value(profile + "/Position");
39− if (!pos.isValid())
40− pos = settings.value("Indicator Service/Position", QVariant::fromValue(0));
45+ setId(settings.value("Indicator Service/Name").toString());
41− setPosition(pos.toInt());
42
46
43 QString actionObjectPath = settings.value("Indicator Service/ObjectPath").toString();
47 QString actionObjectPath = settings.value("Indicator Service/ObjectPath").toString();
44− QString menuObjectPath = settings.value(profile + "/ObjectPath").toString();
45
48
46 QVariantMap properties;
49 QVariantMap properties;
47 properties.clear();
50 properties.clear();
48 properties.insert("busType", 1);
51 properties.insert("busType", 1);
49 properties.insert("busName", busName);
52 properties.insert("busName", busName);
50 properties.insert("actionsObjectPath", actionObjectPath);
53 properties.insert("actionsObjectPath", actionObjectPath);
51− properties.insert("menuObjectPath", menuObjectPath);
54+
52− setIndicatorProperties(properties);
55+ m_properties = properties;
56+ setProfile(profile); // will emit changed signals for us and set position
53}
57}
54
58
55QString Indicator::identifier() const
59QString Indicator::identifier() const
@@ -78,6 +82,19 @@ void Indicator::setPosition(int position)
78 }
82 }
79}
83}
80
84
85+void Indicator::setProfile(const QString& profile)
86+{
87+ QVariant pos = m_settings.value(profile + "/Position");
88+ if (!pos.isValid())
89+ pos = m_settings.value("Indicator Service/Position", QVariant::fromValue(0));
90+ setPosition(pos.toInt());
91+
92+ QString menuObjectPath = m_settings.value(profile + "/ObjectPath").toString();
93+ QVariantMap map = m_properties.toMap();
94+ map.insert("menuObjectPath", menuObjectPath);
95+ setIndicatorProperties(map);
96+}
97+
81QVariant Indicator::indicatorProperties() const
98QVariant Indicator::indicatorProperties() const
82{
99{
83 return m_properties;
100 return m_properties;
plugins/Unity/Indicators/indicator.h+4
@@ -41,6 +41,9 @@ public:
41 int position() const;
41 int position() const;
42 QVariant indicatorProperties() const;
42 QVariant indicatorProperties() const;
43
43
44+public Q_SLOTS:
45+ void setProfile(const QString& profile);
46+
44Q_SIGNALS:
47Q_SIGNALS:
45 void identifierChanged(const QString &identifier);
48 void identifierChanged(const QString &identifier);
46 void positionChanged(int position);
49 void positionChanged(int position);
@@ -55,6 +58,7 @@ private:
55 QString m_identifier;
58 QString m_identifier;
56 int m_position;
59 int m_position;
57 QVariant m_properties;
60 QVariant m_properties;
61+ QVariantMap m_settings;
58};
62};
59
63
60#endif // INDICATOR_H
64#endif // INDICATOR_H
plugins/Unity/Indicators/indicatorsmanager.cpp+15−1
@@ -57,7 +57,7 @@ IndicatorsManager::~IndicatorsManager()
57void IndicatorsManager::load(const QString& profile)
57void IndicatorsManager::load(const QString& profile)
58{
58{
59 unload();
59 unload();
60− m_profile = profile;
60+ setProfile(profile);
61
61
62 QStringList xdgLocations = shellDataDirs();//QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation);
62 QStringList xdgLocations = shellDataDirs();//QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation);
63
63
@@ -216,6 +216,19 @@ void IndicatorsManager::setLoaded(bool loaded)
216 }
216 }
217}
217}
218
218
219+QString IndicatorsManager::profile() const
220+{
221+ return m_profile;
222+}
223+
224+void IndicatorsManager::setProfile(const QString& profile)
225+{
226+ if (m_profile != profile) {
227+ m_profile = profile;
228+ Q_EMIT profileChanged(m_profile);
229+ }
230+}
231+
219void IndicatorsManager::startVerify(const QString& path)
232void IndicatorsManager::startVerify(const QString& path)
220{
233{
221 QHashIterator<QString, IndicatorData*> iter(m_indicatorsData);
234 QHashIterator<QString, IndicatorData*> iter(m_indicatorsData);
@@ -269,6 +282,7 @@ Indicator::Ptr IndicatorsManager::indicator(const QString& indicator_name)
269 data->m_indicator = new_indicator;
282 data->m_indicator = new_indicator;
270 QSettings settings(data->m_fileInfo.absoluteFilePath(), QSettings::IniFormat, this);
283 QSettings settings(data->m_fileInfo.absoluteFilePath(), QSettings::IniFormat, this);
271 new_indicator->init(m_profile, data->m_fileInfo.fileName(), settings);
284 new_indicator->init(m_profile, data->m_fileInfo.fileName(), settings);
285+ QObject::connect(this, SIGNAL(profileChanged(const QString&)), new_indicator.data(), SLOT(setProfile(const QString&)));
272 return new_indicator;
286 return new_indicator;
273}
287}
274
288
plugins/Unity/Indicators/indicatorsmanager.h+5
@@ -32,6 +32,7 @@ class UNITYINDICATORS_EXPORT IndicatorsManager : public QObject
32{
32{
33 Q_OBJECT
33 Q_OBJECT
34 Q_PROPERTY(bool loaded READ isLoaded NOTIFY loadedChanged)
34 Q_PROPERTY(bool loaded READ isLoaded NOTIFY loadedChanged)
35+ Q_PROPERTY(QString profile READ profile WRITE setProfile NOTIFY profileChanged)
35public:
36public:
36 explicit IndicatorsManager(QObject* parent = 0);
37 explicit IndicatorsManager(QObject* parent = 0);
37 ~IndicatorsManager();
38 ~IndicatorsManager();
@@ -39,6 +40,9 @@ public:
39 Q_INVOKABLE void load(const QString& profile);
40 Q_INVOKABLE void load(const QString& profile);
40 Q_INVOKABLE void unload();
41 Q_INVOKABLE void unload();
41
42
43+ QString profile() const;
44+ void setProfile(const QString& profile);
45+
42 Indicator::Ptr indicator(const QString& indicator_name);
46 Indicator::Ptr indicator(const QString& indicator_name);
43
47
44 QList<Indicator::Ptr> indicators();
48 QList<Indicator::Ptr> indicators();
@@ -47,6 +51,7 @@ public:
47
51
48Q_SIGNALS:
52Q_SIGNALS:
49 void loadedChanged(bool);
53 void loadedChanged(bool);
54+ void profileChanged(const QString&);
50
55
51 void indicatorLoaded(const QString& indicator_name);
56 void indicatorLoaded(const QString& indicator_name);
52 void indicatorAboutToBeUnloaded(const QString& indicator_name);
57 void indicatorAboutToBeUnloaded(const QString& indicator_name);
plugins/Unity/Indicators/indicatorsmodel.cpp+23
@@ -56,6 +56,7 @@ IndicatorsModel::IndicatorsModel(QObject *parent)
56 m_manager = new IndicatorsManager(this);
56 m_manager = new IndicatorsManager(this);
57 QObject::connect(m_manager, SIGNAL(indicatorLoaded(const QString&)), this, SLOT(onIndicatorLoaded(const QString&)));
57 QObject::connect(m_manager, SIGNAL(indicatorLoaded(const QString&)), this, SLOT(onIndicatorLoaded(const QString&)));
58 QObject::connect(m_manager, SIGNAL(indicatorAboutToBeUnloaded(const QString&)), this, SLOT(onIndicatorAboutToBeUnloaded(const QString&)));
58 QObject::connect(m_manager, SIGNAL(indicatorAboutToBeUnloaded(const QString&)), this, SLOT(onIndicatorAboutToBeUnloaded(const QString&)));
59+ QObject::connect(m_manager, SIGNAL(profileChanged(const QString&)), this, SIGNAL(profileChanged()));
59
60
60 QObject::connect(this, SIGNAL(rowsInserted(const QModelIndex &, int, int)), this, SIGNAL(countChanged()));
61 QObject::connect(this, SIGNAL(rowsInserted(const QModelIndex &, int, int)), this, SIGNAL(countChanged()));
61 QObject::connect(this, SIGNAL(rowsRemoved(const QModelIndex &, int, int)), this, SIGNAL(countChanged()));
62 QObject::connect(this, SIGNAL(rowsRemoved(const QModelIndex &, int, int)), this, SIGNAL(countChanged()));
@@ -80,6 +81,28 @@ int IndicatorsModel::count() const
80 return rowCount();
81 return rowCount();
81}
82}
82
83
84+/*!
85+ \qmlproperty IndicatorsModel::profile
86+ The indicator profile to use for the model.
87+
88+ \b Note: methods should only be called after the Component has completed.
89+*/
90+QString IndicatorsModel::profile() const
91+{
92+ return m_manager->profile();
93+}
94+
95+/*!
96+ \qmlproperty IndicatorsModel::setProfile
97+ Set the indicator profile to use for the model.
98+
99+ \b Note: methods should only be called after the Component has completed.
100+*/
101+void IndicatorsModel::setProfile(const QString &profile)
102+{
103+ m_manager->setProfile(profile);
104+}
105+
83/*!
106/*!
84 \qmlmethod IndicatorsModel::unload()
107 \qmlmethod IndicatorsModel::unload()
85
108
plugins/Unity/Indicators/indicatorsmodel.h+5
@@ -34,6 +34,7 @@ class UNITYINDICATORS_EXPORT IndicatorsModel : public QAbstractListModel
34 Q_OBJECT
34 Q_OBJECT
35 Q_ENUMS(Roles)
35 Q_ENUMS(Roles)
36 Q_PROPERTY(int count READ count NOTIFY countChanged)
36 Q_PROPERTY(int count READ count NOTIFY countChanged)
37+ Q_PROPERTY(QString profile READ profile WRITE setProfile NOTIFY profileChanged)
37
38
38public:
39public:
39
40
@@ -45,6 +46,9 @@ public:
45
46
46 Q_INVOKABLE QVariant data(int row, int role) const;
47 Q_INVOKABLE QVariant data(int row, int role) const;
47
48
49+ QString profile() const;
50+ void setProfile(const QString& profile);
51+
48 /* QAbstractItemModel */
52 /* QAbstractItemModel */
49 QHash<int, QByteArray> roleNames() const;
53 QHash<int, QByteArray> roleNames() const;
50 int columnCount(const QModelIndex &parent = QModelIndex()) const;
54 int columnCount(const QModelIndex &parent = QModelIndex()) const;
@@ -55,6 +59,7 @@ public:
55
59
56Q_SIGNALS:
60Q_SIGNALS:
57 void countChanged();
61 void countChanged();
62+ void profileChanged();
58 void indicatorDataChanged(const QVariant& data);
63 void indicatorDataChanged(const QVariant& data);
59
64
60private Q_SLOTS:
65private Q_SLOTS:
plugins/Unity/Indicators/rootactionstate.cpp+3−1
@@ -110,9 +110,11 @@ void RootActionState::updateActionState()
110 m_cachedState = m_menu->get(0, "actionState").toMap();
110 m_cachedState = m_menu->get(0, "actionState").toMap();
111
111
112 m_menu->setActionStateParser(oldParser);
112 m_menu->setActionStateParser(oldParser);
113− } else {
113+ } else if (!m_menu) {
114 m_cachedState.clear();
114 m_cachedState.clear();
115 }
115 }
116+ // else if m_menu->rowCount() == 0, let's leave existing cache in place
117+ // until the new menu comes in, to avoid flashing the UI empty for a moment
116 Q_EMIT updated();
118 Q_EMIT updated();
117}
119}
118
120
plugins/Unity/Indicators/unitymenumodelcache.cpp+6−7
@@ -36,13 +36,12 @@ UnityMenuModel* UnityMenuModelCache::model(const QByteArray& bus,
36 if (m_registry.contains(path))
36 if (m_registry.contains(path))
37 return m_registry[path];
37 return m_registry[path];
38
38
39+ // Parent the model to us, so it is not deleted by Qml. We want to keep
40+ // all models cached, because when we switch indicator profiles, we will
41+ // be switching paths often. And we want to keep the old model around,
42+ // ready to be used. Otherwise the UI might momentarily wait as we
43+ // populate the model from DBus yet again.
39− UnityMenuModel* menuModel = new UnityMenuModel;
44+ UnityMenuModel* menuModel = new UnityMenuModel(this);
40− connect(menuModel, &QObject::destroyed, this, [menuModel, this](QObject*) {
41− QList<QByteArray> keys = m_registry.keys(menuModel);
42− Q_FOREACH(const QByteArray& key, keys) {
43− m_registry.remove(key);
44− }
45− });
46 m_registry[path] = menuModel;
45 m_registry[path] = menuModel;
47
46
48 menuModel->setBusName(bus);
47 menuModel->setBusName(bus);
qml/Panel/IndicatorItem.qml+9−1
@@ -31,7 +31,7 @@ Loader {
31 opacity: dimmed ? 0.4 : 1
31 opacity: dimmed ? 0.4 : 1
32 Behavior on opacity { UbuntuNumberAnimation { duration: UbuntuAnimation.BriskDuration } }
32 Behavior on opacity { UbuntuNumberAnimation { duration: UbuntuAnimation.BriskDuration } }
33
33
34− onLoaded: {
34+ function updateProperties() {
35 for(var pName in indicatorProperties) {
35 for(var pName in indicatorProperties) {
36 if (item.hasOwnProperty(pName)) {
36 if (item.hasOwnProperty(pName)) {
37 item[pName] = indicatorProperties[pName];
37 item[pName] = indicatorProperties[pName];
@@ -39,6 +39,14 @@ Loader {
39 }
39 }
40 }
40 }
41
41
42+ onLoaded: updateProperties()
43+
44+ onIndicatorPropertiesChanged: {
45+ if (status === Loader.Ready) {
46+ updateProperties()
47+ }
48+ }
49+
42 Binding {
50 Binding {
43 target: item
51 target: item
44 property: "identifier"
52 property: "identifier"
qml/Panel/Indicators.qml+1−2
@@ -30,8 +30,7 @@ Showable {
30 property int panelHeight: units.gu(3)
30 property int panelHeight: units.gu(3)
31 property alias overFlowWidth: indicatorRow.overFlowWidth
31 property alias overFlowWidth: indicatorRow.overFlowWidth
32 property alias showAll: indicatorRow.showAll
32 property alias showAll: indicatorRow.showAll
33− // TODO: This should be sourced by device type (eg "desktop", "tablet", "phone"...)
33+ property alias profile: visibleIndicators.profile
34− property string profile: indicatorProfile
35
34
36 readonly property real hintValue: panelHeight + menuContent.headerHeight
35 readonly property real hintValue: panelHeight + menuContent.headerHeight
37 readonly property int lockThreshold: openedHeight / 2
36 readonly property int lockThreshold: openedHeight / 2
qml/Panel/Indicators/DefaultIndicatorPage.qml−1
@@ -125,7 +125,6 @@ IndicatorBase {
125 delegate: Loader {
125 delegate: Loader {
126 id: loader
126 id: loader
127 objectName: "menuItem" + index
127 objectName: "menuItem" + index
128− asynchronous: true
129 width: ListView.view.width
128 width: ListView.view.width
130 visible: status == Loader.Ready
129 visible: status == Loader.Ready
131
130
qml/Panel/Indicators/DefaultIndicatorWidget.qml+2−1
@@ -113,7 +113,8 @@ IndicatorBase {
113
113
114 leftLabel = rootActionState.leftLabel ? rootActionState.leftLabel : "";
114 leftLabel = rootActionState.leftLabel ? rootActionState.leftLabel : "";
115 rightLabel = rootActionState.rightLabel ? rootActionState.rightLabel : "";
115 rightLabel = rootActionState.rightLabel ? rootActionState.rightLabel : "";
116+ if (icons !== rootActionState.icons) // don't reset visual unless we need to
116− icons = rootActionState.icons;
117+ icons = rootActionState.icons;
117 enabled = rootActionState.visible;
118 enabled = rootActionState.visible;
118 }
119 }
119}
120}
qml/Panel/Indicators/VisibleIndicators.qml+13−2
@@ -23,6 +23,7 @@ import Utils 0.1
23
23
24Item {
24Item {
25 property SortFilterProxyModel model: filterModel
25 property SortFilterProxyModel model: filterModel
26+ property alias profile: indicatorsModel.profile
26
27
27 SortFilterProxyModel {
28 SortFilterProxyModel {
28 id: filterModel
29 id: filterModel
@@ -56,13 +57,23 @@ Item {
56 id: item
57 id: item
57 objectName: model.identifier + "-delegate"
58 objectName: model.identifier + "-delegate"
58 identifier: model.identifier
59 identifier: model.identifier
59− Component.onCompleted: {
60+
61+ function updateProperties() {
60 for(var pName in indicatorProperties) {
62 for(var pName in indicatorProperties) {
61 if (item.hasOwnProperty(pName)) {
63 if (item.hasOwnProperty(pName)) {
62 item[pName] = indicatorProperties[pName];
64 item[pName] = indicatorProperties[pName];
63 }
65 }
64 }
66 }
67+ }
68+
69+ Component.onCompleted: {
70+ updateProperties()
65− updateVisibility();
71+ updateVisibility()
72+ }
73+
74+ Connections {
75+ target: indicatorsModel
76+ onDataChanged: item.updateProperties()
66 }
77 }
67
78
68 onEnabledChanged: {
79 onEnabledChanged: {
qml/Panel/MenuContent.qml+15−2
@@ -69,13 +69,20 @@ Rectangle {
69
69
70 IndicatorDelegate {
70 IndicatorDelegate {
71 id: indicatorDelegate
71 id: indicatorDelegate
72− Component.onCompleted: {
72+
73+ function updateProperties() {
73 for(var pName in indicatorProperties) {
74 for(var pName in indicatorProperties) {
74 if (indicatorDelegate.hasOwnProperty(pName)) {
75 if (indicatorDelegate.hasOwnProperty(pName)) {
75 indicatorDelegate[pName] = indicatorProperties[pName];
76 indicatorDelegate[pName] = indicatorProperties[pName];
76 }
77 }
77 }
78 }
78 }
79 }
80+
81+ Component.onCompleted: updateProperties()
82+ Connections {
83+ target: content.indicatorsModel
84+ onDataChanged: indicatorDelegate.updateProperties()
85+ }
79 }
86 }
80 }
87 }
81 }
88 }
@@ -115,7 +122,7 @@ Rectangle {
115 }
122 }
116 }
123 }
117
124
118− onLoaded: {
125+ function updateProperties() {
119 for(var pName in indicatorProperties) {
126 for(var pName in indicatorProperties) {
120 if (item.hasOwnProperty(pName)) {
127 if (item.hasOwnProperty(pName)) {
121 item[pName] = indicatorProperties[pName]
128 item[pName] = indicatorProperties[pName]
@@ -123,6 +130,12 @@ Rectangle {
123 }
130 }
124 }
131 }
125
132
133+ onLoaded: updateProperties()
134+ Connections {
135+ target: content.indicatorsModel
136+ onDataChanged: if (loader.status === Loader.Ready) loader.updateProperties()
137+ }
138+
126 Binding {
139 Binding {
127 target: loader.item
140 target: loader.item
128 property: "identifier"
141 property: "identifier"
qml/Shell.qml+3
@@ -574,6 +574,9 @@ Item {
574 contentEnabled: edgeDemo.panelContentEnabled
574 contentEnabled: edgeDemo.panelContentEnabled
575 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
575 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
576 panelHeight: units.gu(3)
576 panelHeight: units.gu(3)
577+
578+ // TODO: This should be sourced by device type (eg "desktop", "tablet", "phone"...)
579+ profile: LightDM.Greeter.active ? (indicatorProfile + "_greeter") : indicatorProfile
577 }
580 }
578
581
579 property bool topmostApplicationIsFullscreen:
582 property bool topmostApplicationIsFullscreen: