on bionic help sign in
unity8/plugins/Unity/Indicators/indicatorsmanager.cpp
313 lines 8.6 kB history raw
1/*
2 * Copyright (C) 2013-2016 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 */
17#include "indicatorsmanager.h"
19#include <QSettings>
20#include <QDebug>
22#include <paths.h>
25class IndicatorsManager::IndicatorData
27public:
28 IndicatorData(const QString& name, const QFileInfo& fileInfo)
29 : m_name(name)
30 , m_fileInfo(fileInfo)
31 , m_verified (true)
32 {
33 }
35 QString m_name;
36 QFileInfo m_fileInfo;
38 bool m_verified;
39 Indicator::Ptr m_indicator;
40};
42IndicatorsManager::IndicatorsManager(QObject* parent)
43 : QObject(parent)
44 , m_loaded(false)
45 , m_profile(QStringLiteral("phone"))
49IndicatorsManager::~IndicatorsManager()
51 unload();
54void IndicatorsManager::load()
56 unload();
58 const QStringList xdgLocations = shellDataDirs();
60 m_fsWatcher.reset(new QFileSystemWatcher(this));
62 Q_FOREACH(const QString& xdgLocation, xdgLocations)
63 {
64 const QString indicator_path = QDir::cleanPath(xdgLocation + "/unity/indicators");
65 QDir indicator_dir(indicator_path);
66 if (indicator_dir.exists())
67 {
68 // watch folder for changes.
69 m_fsWatcher->addPath(indicator_path);
71 loadDir(indicator_dir);
72 }
73 }
75 QObject::connect(m_fsWatcher.data(), &QFileSystemWatcher::directoryChanged, this, &IndicatorsManager::onDirectoryChanged);
76 QObject::connect(m_fsWatcher.data(), &QFileSystemWatcher::fileChanged, this, &IndicatorsManager::onFileChanged);
77 setLoaded(true);
80void IndicatorsManager::onDirectoryChanged(const QString& directory)
82 loadDir(QDir(directory));
85void IndicatorsManager::onFileChanged(const QString& file)
87 QFileInfo file_info(file);
88 if (!file_info.exists())
89 {
90 unloadFile(file_info);
91 return;
92 }
93 else
94 {
95 loadFile(QFileInfo(file));
96 }
99void IndicatorsManager::loadDir(const QDir& dir)
101 startVerify(dir.canonicalPath());
103 const QFileInfoList indicator_files = dir.entryInfoList(QStringList(), QDir::Files|QDir::NoDotAndDotDot);
104 Q_FOREACH(const QFileInfo& indicator_file, indicator_files)
105 {
106 loadFile(indicator_file);
107 }
109 endVerify(dir.canonicalPath());
112void IndicatorsManager::loadFile(const QFileInfo& file_info)
114 QSettings indicator_settings(file_info.absoluteFilePath(), QSettings::IniFormat, this);
115 const QString name = indicator_settings.value(QStringLiteral("Indicator Service/Name")).toString();
117 auto iter = m_indicatorsData.constFind(name);
118 if (iter != m_indicatorsData.constEnd())
119 {
120 const QString newFileInfoDir = QDir::cleanPath(file_info.canonicalPath());
121 IndicatorData* currentData = (*iter);
122 currentData->m_verified = true;
124 int file_info_location = -1;
125 int current_data_location = -1;
127 const QString currentDataDir = QDir::cleanPath(currentData->m_fileInfo.canonicalPath());
129 // if we've already got this indicator, we need to make sure we're not overwriting data which is
130 // from a lower priority standard path
131 QStringList xdgLocations = shellDataDirs();
132 for (int i = 0; i < xdgLocations.size(); i++)
133 {
134 const QString indicatorDir = QDir::cleanPath(xdgLocations[i] + "/unity/indicators");
136 if (newFileInfoDir == indicatorDir)
137 {
138 file_info_location = i;
139 }
140 if (currentDataDir == indicatorDir)
141 {
142 current_data_location = i;
143 }
145 if (file_info_location != -1 && current_data_location != -1)
146 {
147 break;
148 }
149 }
151 // file location is higher (or of equal) priority. overwrite.
152 if (file_info_location <= current_data_location &&
153 file_info != currentData->m_fileInfo)
154 {
155 currentData->m_fileInfo = file_info;
156 Q_EMIT indicatorLoaded(name);
157 }
158 }
159 else
160 {
161 IndicatorData* data = new IndicatorData(name, file_info);
162 data->m_verified = true;
163 m_indicatorsData[name]= data;
164 Q_EMIT indicatorLoaded(name);
165 }
168void IndicatorsManager::unload()
170 QHashIterator<QString, IndicatorData*> iter(m_indicatorsData);
171 while(iter.hasNext())
172 {
173 iter.next();
174 Q_EMIT indicatorAboutToBeUnloaded(iter.key());
175 }
177 qDeleteAll(m_indicatorsData);
178 m_indicatorsData.clear();
180 setLoaded(false);
183void IndicatorsManager::unloadFile(const QFileInfo& file)
185 QMutableHashIterator<QString, IndicatorData*> iter(m_indicatorsData);
186 while(iter.hasNext())
187 {
188 iter.next();
189 IndicatorData* data = iter.value();
190 if (data->m_fileInfo.absoluteFilePath() == file.absoluteFilePath())
191 {
192 if (!data->m_verified)
193 {
194 const QString name = data->m_name;
195 Q_EMIT indicatorAboutToBeUnloaded(name);
197 delete data;
198 iter.remove();
199 }
200 }
201 }
203 setLoaded(m_indicatorsData.size() > 0);
206void IndicatorsManager::setLoaded(bool loaded)
208 if (loaded != m_loaded)
209 {
210 m_loaded = loaded;
211 Q_EMIT loadedChanged(m_loaded);
212 }
215QString IndicatorsManager::profile() const
217 return m_profile;
220void IndicatorsManager::setProfile(const QString& profile)
222 if (m_profile != profile) {
223 m_profile = profile;
224 Q_EMIT profileChanged(m_profile);
225 }
228void IndicatorsManager::startVerify(const QString& path)
230 QHashIterator<QString, IndicatorData*> iter(m_indicatorsData);
231 while(iter.hasNext())
232 {
233 iter.next();
234 IndicatorData* data = iter.value();
235 if (data->m_fileInfo.canonicalPath() == path)
236 {
237 data->m_verified = false;
238 }
239 }
242void IndicatorsManager::endVerify(const QString& path)
244 QMutableHashIterator<QString, IndicatorData*> iter(m_indicatorsData);
245 while(iter.hasNext())
246 {
247 iter.next();
248 IndicatorData* data = iter.value();
249 if (data->m_fileInfo.canonicalPath() == path)
250 {
251 if (!data->m_verified)
252 {
253 const QString name = data->m_name;
254 Q_EMIT indicatorAboutToBeUnloaded(name);
256 delete data;
257 iter.remove();
258 }
259 }
260 }
263Indicator::Ptr IndicatorsManager::indicator(const QString& indicator_name)
265 if (!m_indicatorsData.contains(indicator_name))
266 {
267 qWarning() << Q_FUNC_INFO << "Invalid indicator name: " << indicator_name;
268 return Indicator::Ptr();
269 }
271 IndicatorData *data = m_indicatorsData.value(indicator_name);
272 if (data->m_indicator)
273 {
274 return data->m_indicator;
275 }
277 Indicator::Ptr new_indicator(new Indicator(this));
278 data->m_indicator = new_indicator;
279 QSettings settings(data->m_fileInfo.absoluteFilePath(), QSettings::IniFormat, this);
280 new_indicator->init(data->m_fileInfo.fileName(), settings);
282 // convergence:
283 // 1) enable session indicator
284 // 2) enable keyboard indicator
285 //
286 // The rest of the indicators respect their default profile (which is "phone", even on desktop PCs)
287 if ((new_indicator->identifier() == QStringLiteral("indicator-session"))
288 || new_indicator->identifier() == QStringLiteral("indicator-keyboard")) {
289 new_indicator->setProfile(QString(m_profile).replace(QStringLiteral("phone"), QStringLiteral("desktop")));
290 } else {
291 new_indicator->setProfile(m_profile);
292 }
294 QObject::connect(this, &IndicatorsManager::profileChanged, new_indicator.data(), &Indicator::setProfile);
295 return new_indicator;
298QVector<Indicator::Ptr> IndicatorsManager::indicators()
300 QVector<Indicator::Ptr> list;
301 Q_FOREACH(IndicatorData* data, m_indicatorsData)
302 {
303 Indicator::Ptr ret = indicator(data->m_name);
304 if (ret)
305 list.append(ret);
306 }
307 return list;
310bool IndicatorsManager::isLoaded() const
312 return m_loaded;