Unity 8
 All Classes Functions Properties
indicatorsmanager.cpp
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  * Author: Nick Dedekind <nick.dedekind@canonical.com>
17  */
18 
19 #include "indicatorsmanager.h"
20 
21 #include <QSettings>
22 #include <QDebug>
23 
24 #include <paths.h>
25 
26 
27 class IndicatorsManager::IndicatorData
28 {
29 public:
30  IndicatorData(const QString& name, const QFileInfo& fileInfo)
31  : m_name(name)
32  , m_fileInfo(fileInfo)
33  , m_verified (true)
34  {
35  }
36 
37  QString m_name;
38  QFileInfo m_fileInfo;
39 
40  bool m_verified;
41  Indicator::Ptr m_indicator;
42 };
43 
44 IndicatorsManager::IndicatorsManager(QObject* parent)
45  : QObject(parent)
46  , m_loaded(false)
47  , m_profile("phone")
48 {
49 }
50 
51 IndicatorsManager::~IndicatorsManager()
52 {
53  unload();
54 
55 }
56 
57 void IndicatorsManager::load(const QString& profile)
58 {
59  unload();
60  m_profile = profile;
61 
62  QStringList xdgLocations = shellDataDirs();//QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation);
63 
64  m_fsWatcher.reset(new QFileSystemWatcher(this));
65 
66  Q_FOREACH(const QString& xdgLocation, xdgLocations)
67  {
68  QString indicator_path = QDir::cleanPath(xdgLocation + "/unity/indicators");
69  QDir indicator_dir(indicator_path);
70  if (indicator_dir.exists())
71  {
72  // watch folder for changes.
73  m_fsWatcher->addPath(indicator_path);
74 
75  loadDir(indicator_dir);
76  }
77  }
78 
79  QObject::connect(m_fsWatcher.data(), SIGNAL(directoryChanged(const QString&)), this, SLOT(onDirectoryChanged(const QString&)));
80  QObject::connect(m_fsWatcher.data(), SIGNAL(fileChanged(const QString&)), this, SLOT(onFileChanged(const QString&)));
81  setLoaded(true);
82 }
83 
84 void IndicatorsManager::onDirectoryChanged(const QString& directory)
85 {
86  loadDir(QDir(directory));
87 }
88 
89 void IndicatorsManager::onFileChanged(const QString& file)
90 {
91  QFileInfo file_info(file);
92  if (!file_info.exists())
93  {
94  unloadFile(file_info);
95  return;
96  }
97  else
98  {
99  loadFile(QFileInfo(file));
100  }
101 }
102 
103 void IndicatorsManager::loadDir(const QDir& dir)
104 {
105  startVerify(dir.canonicalPath());
106 
107  QFileInfoList indicator_files = dir.entryInfoList(QStringList(), QDir::Files|QDir::NoDotAndDotDot);
108  Q_FOREACH(const QFileInfo& indicator_file, indicator_files)
109  {
110  loadFile(indicator_file);
111  }
112 
113  endVerify(dir.canonicalPath());
114 }
115 
116 void IndicatorsManager::loadFile(const QFileInfo& file_info)
117 {
118  QSettings indicator_settings(file_info.absoluteFilePath(), QSettings::IniFormat, this);
119  QString name = indicator_settings.value("Indicator Service/Name").toString();
120 
121  auto iter = m_indicatorsData.find(name);
122  if (iter != m_indicatorsData.end())
123  {
124  QString newFileInfoDir = QDir::cleanPath(file_info.canonicalPath());
125  IndicatorData* currentData = (*iter);
126  currentData->m_verified = true;
127 
128  int file_info_location = -1;
129  int current_data_location = -1;
130 
131  QString currentDataDir = QDir::cleanPath(currentData->m_fileInfo.canonicalPath());
132 
133  // if we've already got this indicator, we need to make sure we're not overwriting data which is
134  // from a lower priority standard path
135  QStringList xdgLocations = shellDataDirs();
136  for (int i = 0; i < xdgLocations.size(); i++)
137  {
138  QString indicatorDir = QDir::cleanPath(xdgLocations[i] + "/unity/indicators");
139 
140  if (newFileInfoDir == indicatorDir)
141  {
142  file_info_location = i;
143  }
144  if (currentDataDir == indicatorDir)
145  {
146  current_data_location = i;
147  }
148 
149  if (file_info_location != -1 && current_data_location != -1)
150  {
151  break;
152  }
153  }
154 
155  // file location is higher (or of equal) priority. overwrite.
156  if (file_info_location <= current_data_location &&
157  file_info != currentData->m_fileInfo)
158  {
159  currentData->m_fileInfo = file_info;
160  Q_EMIT indicatorLoaded(name);
161  }
162  }
163  else
164  {
165  IndicatorData* data = new IndicatorData(name, file_info);
166  data->m_verified = true;
167  m_indicatorsData[name]= data;
168  Q_EMIT indicatorLoaded(name);
169  }
170 }
171 
172 void IndicatorsManager::unload()
173 {
174  QHashIterator<QString, IndicatorData*> iter(m_indicatorsData);
175  while(iter.hasNext())
176  {
177  iter.next();
178  Q_EMIT indicatorAboutToBeUnloaded(iter.key());
179  }
180 
181  qDeleteAll(m_indicatorsData);
182  m_indicatorsData.clear();
183 
184  setLoaded(false);
185 }
186 
187 void IndicatorsManager::unloadFile(const QFileInfo& file)
188 {
189  QMutableHashIterator<QString, IndicatorData*> iter(m_indicatorsData);
190  while(iter.hasNext())
191  {
192  iter.next();
193  IndicatorData* data = iter.value();
194  if (data->m_fileInfo.absoluteFilePath() == file.absoluteFilePath())
195  {
196  if (!data->m_verified)
197  {
198  QString name = data->m_name;
199  Q_EMIT indicatorAboutToBeUnloaded(name);
200 
201  delete data;
202  iter.remove();
203  }
204  }
205  }
206 
207  setLoaded(m_indicatorsData.size() > 0);
208 }
209 
210 void IndicatorsManager::setLoaded(bool loaded)
211 {
212  if (loaded != m_loaded)
213  {
214  m_loaded = loaded;
215  Q_EMIT loadedChanged(m_loaded);
216  }
217 }
218 
219 void IndicatorsManager::startVerify(const QString& path)
220 {
221  QHashIterator<QString, IndicatorData*> iter(m_indicatorsData);
222  while(iter.hasNext())
223  {
224  iter.next();
225  IndicatorData* data = iter.value();
226  if (data->m_fileInfo.canonicalPath() == path)
227  {
228  data->m_verified = false;
229  }
230  }
231 }
232 
233 void IndicatorsManager::endVerify(const QString& path)
234 {
235  QMutableHashIterator<QString, IndicatorData*> iter(m_indicatorsData);
236  while(iter.hasNext())
237  {
238  iter.next();
239  IndicatorData* data = iter.value();
240  if (data->m_fileInfo.canonicalPath() == path)
241  {
242  if (!data->m_verified)
243  {
244  QString name = data->m_name;
245  Q_EMIT indicatorAboutToBeUnloaded(name);
246 
247  delete data;
248  iter.remove();
249  }
250  }
251  }
252 }
253 
254 Indicator::Ptr IndicatorsManager::indicator(const QString& indicator_name)
255 {
256  if (!m_indicatorsData.contains(indicator_name))
257  {
258  qWarning() << Q_FUNC_INFO << "Invalid indicator name: " << indicator_name;
259  return Indicator::Ptr();
260  }
261 
262  IndicatorData *data = m_indicatorsData[indicator_name];
263  if (data->m_indicator)
264  {
265  return data->m_indicator;
266  }
267 
268  Indicator::Ptr new_indicator(new Indicator(this));
269  data->m_indicator = new_indicator;
270  QSettings settings(data->m_fileInfo.absoluteFilePath(), QSettings::IniFormat, this);
271  new_indicator->init(m_profile, data->m_fileInfo.fileName(), settings);
272  return new_indicator;
273 }
274 
275 QList<Indicator::Ptr> IndicatorsManager::indicators()
276 {
277  QList<Indicator::Ptr> list;
278  Q_FOREACH(IndicatorData* data, m_indicatorsData)
279  {
280  Indicator::Ptr ret = indicator(data->m_name);
281  if (ret)
282  list.append(ret);
283  }
284  return list;
285 }
286 
287 bool IndicatorsManager::isLoaded() const
288 {
289  return m_loaded;
290 }