1 /* |
|
2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0"" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 #include "cpthemechanger.h" |
|
19 #include "cpthemechanger_p.h" |
|
20 #include <QStringList> |
|
21 #include <QSettings> |
|
22 #include <QFileSystemWatcher> |
|
23 #include <QPixmap> |
|
24 #include <QSizeF> |
|
25 #include <hbicon.h> |
|
26 #include <hbinstance.h> |
|
27 #include "cpthemeclient_p.h" |
|
28 #include "cpthemecommon_p.h" |
|
29 #ifdef Q_OS_SYMBIAN |
|
30 #include "cpthemeclientsymbian_p.h" |
|
31 #else |
|
32 #include "cpthemeclientqt_p.h" |
|
33 #endif |
|
34 |
|
35 namespace { |
|
36 #if !defined(Q_OS_SYMBIAN) |
|
37 #include <stdio.h> |
|
38 static const char* KThemePathKey = "HB_THEMES_DIR"; |
|
39 #endif |
|
40 |
|
41 static const QString KDefaultTheme = "hbdefault"; |
|
42 static const char* KSettingsCategory = "currenttheme"; |
|
43 |
|
44 } |
|
45 |
|
46 CpThemeChangerPrivate::CpThemeChangerPrivate(CpThemeChanger* qq): |
|
47 q_ptr(qq), |
|
48 themeClient(CpThemeClient::global()), |
|
49 fileWatcher(new QFileSystemWatcher(qq)), |
|
50 model(this, qq) |
|
51 |
|
52 { |
|
53 Q_Q(CpThemeChanger); |
|
54 |
|
55 // Figure out where our themes are. This is platform-dependent, |
|
56 // but not worth breaking out into platform-private implementations |
|
57 // at the moment. Ideally, this would be given to us by the theme server, |
|
58 #ifdef Q_OS_WIN |
|
59 static char* _path=NULL; |
|
60 static size_t _size=0; |
|
61 _dupenv_s(&_path, &_size, KThemePathKey); |
|
62 themeRootPath = QString(_path); |
|
63 themeRootPathPostfix = QString(); |
|
64 free(_path); |
|
65 #elif defined(Q_OS_SYMBIAN) |
|
66 themeRootPath = "c:\\resource\\hb"; |
|
67 themeRootPathPostfix = "resource\\hb"; |
|
68 #elif defined(Q_OS_UNIX) |
|
69 themeRootPath = QString(getenv(KThemePathKey)); |
|
70 themeRootPathPostfix = QString(); |
|
71 #elif defined(Q_OS_MACX) |
|
72 themeRootPath = QDir::homePath() + '/' + "Library" + QString("hb"); |
|
73 themeRootPathPostfix = QString(); |
|
74 #else |
|
75 themeRootPath = "c:\\resource\\hb"; |
|
76 themeRootPathPostfix = QString(); |
|
77 #endif |
|
78 |
|
79 // Get our current state |
|
80 QSettings settings(QLatin1String(ORGANIZATION), QLatin1String(THEME_COMPONENT)); |
|
81 mCurrentTheme.name = settings.value(KSettingsCategory).toString(); |
|
82 updateThemeList(mCurrentTheme.name); |
|
83 |
|
84 // Watch for changes to the theme directory in flash. |
|
85 // This may change once we start offering a model. |
|
86 fileWatcher->addPath(themeRootPath+"/themes/"); |
|
87 q->connect(fileWatcher, SIGNAL(directoryChanged(const QString&)), |
|
88 q, SLOT(_q_themeDirectoryChanged(const QString&))); |
|
89 |
|
90 // Connect to the theme server |
|
91 connectToServer(); |
|
92 } |
|
93 |
|
94 CpThemeChangerPrivate::~CpThemeChangerPrivate() |
|
95 { |
|
96 themeClient->releaseInstance(); |
|
97 } |
|
98 |
|
99 const CpThemeChanger::ThemeInfo& CpThemeChangerPrivate::currentTheme() const |
|
100 { |
|
101 return mCurrentTheme; |
|
102 } |
|
103 |
|
104 const QString& CpThemeChangerPrivate::currentThemeName() const |
|
105 { |
|
106 return mCurrentTheme.name.isEmpty() ? KDefaultTheme : mCurrentTheme.name; |
|
107 } |
|
108 |
|
109 int CpThemeChangerPrivate::indexOf(const CpThemeChanger::ThemeInfo& theme) const |
|
110 { |
|
111 return themeList.indexOf(theme); |
|
112 } |
|
113 |
|
114 void CpThemeChangerPrivate::updateThemeList(const QString& newThemeName) |
|
115 { |
|
116 if(!themeList.isEmpty()) { |
|
117 themeList.clear(); |
|
118 } |
|
119 |
|
120 mCurrentTheme.name = newThemeName.isEmpty() ? KDefaultTheme : newThemeName; |
|
121 |
|
122 // Get the list of Drives here |
|
123 QStringList themesPathList; |
|
124 |
|
125 #if defined(Q_OS_WIN32) |
|
126 themesPathList << themeRootPath; |
|
127 #elif defined(Q_OS_SYMBIAN) |
|
128 QFileInfoList driveInfoList = QDir::drives(); |
|
129 foreach (const QFileInfo &driveInfo, driveInfoList) { |
|
130 const QString drive = driveInfo.absolutePath(); |
|
131 themesPathList << drive + themeRootPathPostfix; |
|
132 } |
|
133 #elif defined(Q_OS_UNIX) |
|
134 themesPathList << themeRootPath; |
|
135 #elif defined(Q_OS_MACX) |
|
136 themesPathList << themeRootPath; |
|
137 #endif |
|
138 |
|
139 foreach (const QString &path, themesPathList) { |
|
140 QDir themeDir; |
|
141 themeDir.setPath( path ) ; |
|
142 QStringList iconthemeslist; |
|
143 QStringList list = themeDir.entryList(QDir::AllDirs|QDir::NoDotAndDotDot,QDir::Name); |
|
144 CpThemeChanger::ThemeInfo nameIconPair; |
|
145 |
|
146 if(list.contains("themes",Qt::CaseSensitive )) { |
|
147 QDir root(themeDir.path()); |
|
148 themeDir.setPath(root.path()+"/themes/icons/") ; |
|
149 iconthemeslist=themeDir.entryList(QDir::AllDirs|QDir::NoDotAndDotDot,QDir::Name); |
|
150 foreach(QString themefolder, iconthemeslist) { |
|
151 QDir iconThemePath(root.path()+"/themes/icons/"+themefolder); |
|
152 if(iconThemePath.exists("index.theme") && |
|
153 (iconThemePath.exists("scalable") || iconThemePath.exists("pixmap") )) { |
|
154 QSettings iniSetting(iconThemePath.path()+"/index.theme",QSettings::IniFormat); |
|
155 iniSetting.beginGroup("Icon Theme"); |
|
156 QString hidden = iniSetting.value("Hidden").toString(); |
|
157 QString name = iniSetting.value("Name").toString(); |
|
158 QString iconPath = iniSetting.value("PreviewThumbnailPath").toString(); |
|
159 QString previewPathPrt = iniSetting.value("PreviewIconPath_prt").toString(); |
|
160 QString previewPathLsc = iniSetting.value("PreviewIconPath_lsc").toString(); |
|
161 if (name.isEmpty()) { |
|
162 continue; |
|
163 } |
|
164 |
|
165 QString fullPathToIcon(iconThemePath.path() + iconPath); |
|
166 |
|
167 if(iconPath.isEmpty()|| !QFileInfo(fullPathToIcon).exists()){ |
|
168 |
|
169 //Set thumbnail |
|
170 if(QFileInfo(fullPathToIcon + "/scalable/qtg_graf_theme_preview_thumbnail.svg").exists()){ |
|
171 nameIconPair.icon = HbIcon(fullPathToIcon + "/scalable/qtg_graf_theme_preview_thumbnail.svg"); |
|
172 }else if(QFileInfo(fullPathToIcon + "/scalable/qtg_graf_screen_bg_prt.svg").exists()){ |
|
173 QPixmap px(fullPathToIcon + "/scalable/qtg_graf_screen_bg_prt.svg"); |
|
174 QIcon scaledIcon(px.scaled(QSize(64, 64))); |
|
175 nameIconPair.icon = HbIcon(scaledIcon); |
|
176 nameIconPair.icon.setIconName(fullPathToIcon + "/scalable/qtg_graf_screen_bg_prt.svg"); |
|
177 |
|
178 } else if(QFileInfo(fullPathToIcon + "/pixmap/qtg_graf_screen_bg_prt.png").exists()){ |
|
179 QPixmap px(fullPathToIcon + "/pixmap/qtg_graf_screen_bg_prt.png"); |
|
180 QIcon scaledIcon(px.scaled(QSize(64, 64))); |
|
181 nameIconPair.icon = HbIcon(scaledIcon); |
|
182 nameIconPair.icon.setIconName(fullPathToIcon + "/scalable/qtg_graf_screen_bg_prt.png"); |
|
183 |
|
184 } else{ |
|
185 nameIconPair.icon = HbIcon(":/image/themePreview.svg"); |
|
186 } |
|
187 } else { |
|
188 nameIconPair.icon = HbIcon(fullPathToIcon); |
|
189 } |
|
190 |
|
191 //Portrait preview |
|
192 QString fullPathToPreviewPrt = (iconThemePath.path() + previewPathPrt ); |
|
193 |
|
194 if(previewPathPrt.isEmpty() || !QFileInfo(fullPathToPreviewPrt).exists()) { |
|
195 |
|
196 if(QFileInfo(fullPathToPreviewPrt + "/scalable/qtg_graf_theme_preview_prt.svg").exists()){ |
|
197 nameIconPair.portraitPreviewIcon = HbIcon(fullPathToPreviewPrt + "/scalable/qtg_graf_theme_preview_prt.svg"); |
|
198 }else if(QFileInfo(fullPathToPreviewPrt + "/scalable/qtg_graf_screen_bg_prt.svg").exists()){ |
|
199 nameIconPair.portraitPreviewIcon = HbIcon(fullPathToPreviewPrt + "/scalable/qtg_graf_screen_bg_prt.svg"); |
|
200 } else if(QFileInfo(fullPathToPreviewPrt + "/pixmap/qtg_graf_screen_bg_prt.png").exists()){ |
|
201 nameIconPair.portraitPreviewIcon = HbIcon(fullPathToPreviewPrt + "/pixmap/qtg_graf_screen_bg_prt.png"); |
|
202 } else{ |
|
203 nameIconPair.portraitPreviewIcon = HbIcon(":/image/themePreview.svg"); |
|
204 } |
|
205 } |
|
206 else { |
|
207 nameIconPair.portraitPreviewIcon = HbIcon(fullPathToPreviewPrt); |
|
208 } |
|
209 |
|
210 //Landscape preview |
|
211 QString fullPathToPreviewLsc = (iconThemePath.path() + previewPathLsc ); |
|
212 |
|
213 if(previewPathLsc.isEmpty() || !QFileInfo(fullPathToPreviewLsc).exists()) { |
|
214 |
|
215 if(QFileInfo(fullPathToPreviewLsc + "/scalable/qtg_graf_theme_preview_lsc.svg").exists()){ |
|
216 nameIconPair.landscapePreviewIcon = HbIcon(fullPathToPreviewLsc + "/scalable/qtg_graf_theme_preview_lsc.svg"); |
|
217 }else if(QFileInfo(fullPathToPreviewLsc + "/scalable/qtg_graf_screen_bg_lsc.svg").exists()){ |
|
218 nameIconPair.landscapePreviewIcon = HbIcon(fullPathToPreviewLsc + "/scalable/qtg_graf_screen_bg_lsc.svg"); |
|
219 } else if(QFileInfo(fullPathToPreviewLsc + "/pixmap/qtg_graf_screen_bg_lsc.png").exists()){ |
|
220 nameIconPair.landscapePreviewIcon = HbIcon(fullPathToPreviewLsc + "/pixmap/qtg_graf_screen_bg_lsc.png"); |
|
221 } else{ |
|
222 nameIconPair.landscapePreviewIcon = HbIcon(":/image/themePreview.svg"); |
|
223 } |
|
224 } |
|
225 else { |
|
226 nameIconPair.landscapePreviewIcon = HbIcon(fullPathToPreviewLsc); |
|
227 } |
|
228 |
|
229 nameIconPair.name = name; |
|
230 |
|
231 themeList.append(nameIconPair); |
|
232 |
|
233 if (name == mCurrentTheme.name) { |
|
234 mCurrentTheme = nameIconPair; |
|
235 } |
|
236 |
|
237 iniSetting.endGroup(); |
|
238 if((hidden == "true") ||( hidden == "")||(name!=themefolder) ) { |
|
239 iconthemeslist.removeOne(themefolder); |
|
240 if(!themeList.isEmpty()) { |
|
241 themeList.removeLast(); |
|
242 } |
|
243 } |
|
244 } else { |
|
245 iconthemeslist.removeOne(themefolder); |
|
246 if(!themeList.isEmpty()) { |
|
247 themeList.removeLast(); |
|
248 } |
|
249 } |
|
250 } |
|
251 } |
|
252 } |
|
253 |
|
254 if (mCurrentTheme.name == KDefaultTheme) |
|
255 { |
|
256 // Include default |
|
257 CpThemeChanger::ThemeInfo def; |
|
258 def.name = KDefaultTheme; |
|
259 def.icon = HbIcon(":/image/themePreview.svg"); |
|
260 themeList.append(def); |
|
261 |
|
262 mCurrentTheme = def; |
|
263 } |
|
264 |
|
265 } |
|
266 |
|
267 const QList<CpThemeChanger::ThemeInfo>& CpThemeChangerPrivate::themes() const |
|
268 { |
|
269 return themeList; |
|
270 } |
|
271 |
|
272 bool CpThemeChangerPrivate::connectToServer() |
|
273 { |
|
274 return themeClient->connectToServer(); |
|
275 } |
|
276 |
|
277 /** |
|
278 * Indicate if the client is connected to the server |
|
279 */ |
|
280 bool CpThemeChangerPrivate::isConnected() const |
|
281 { |
|
282 return themeClient->isConnected(); |
|
283 } |
|
284 |
|
285 /** |
|
286 * Change a theme |
|
287 */ |
|
288 bool CpThemeChangerPrivate::changeTheme(const QString& newTheme) |
|
289 { |
|
290 bool result = false; |
|
291 // Skip doing this if the request is for the current theme |
|
292 if (newTheme.isEmpty() || newTheme == mCurrentTheme.name) return result; |
|
293 |
|
294 // Make sure it's a valid theme name |
|
295 bool exists = false; |
|
296 QList<CpThemeChanger::ThemeInfo> themeList = themes(); |
|
297 QList<CpThemeChanger::ThemeInfo>::const_iterator i; |
|
298 for (i = themeList.constBegin(); i != themeList.constEnd(); ++i) { |
|
299 if ( newTheme == i->name) { |
|
300 exists = true; |
|
301 break; |
|
302 } |
|
303 } |
|
304 |
|
305 if (exists) { |
|
306 result = themeClient->changeTheme(newTheme); |
|
307 updateThemeList(newTheme); |
|
308 } |
|
309 return result; |
|
310 } |
|
311 |
|
312 void CpThemeChangerPrivate::_q_themeDirectoryChanged(const QString&) |
|
313 { |
|
314 updateThemeList(); |
|
315 } |
|
316 |
|
317 /* |
|
318 HbThemeChangerModel provides an interface to the data contained in the |
|
319 HbThemeChanger using QAbstractListModel. |
|
320 */ |
|
321 |
|
322 /* |
|
323 Constructor |
|
324 */ |
|
325 HbThemeListModel::HbThemeListModel(CpThemeChangerPrivate *dd, QObject* parent) |
|
326 : QAbstractListModel(parent) |
|
327 , mThemeChangerPrivate(dd) |
|
328 { |
|
329 connect(dd->fileWatcher, SIGNAL(directoryChanged(const QString&)), |
|
330 this, SLOT(themeListChanged())); |
|
331 } |
|
332 |
|
333 /* |
|
334 Destructor |
|
335 */ |
|
336 HbThemeListModel::~HbThemeListModel() |
|
337 { |
|
338 |
|
339 } |
|
340 |
|
341 /* |
|
342 Reimplemented from QAbstractListModel. |
|
343 */ |
|
344 int HbThemeListModel::rowCount(const QModelIndex&) const |
|
345 { |
|
346 return mThemeChangerPrivate->themeList.size(); |
|
347 } |
|
348 |
|
349 /* |
|
350 Reimplemented from QAbstractListModel. Provides the data for Qt::DisplayRole and |
|
351 Qt::DecorationRole. |
|
352 */ |
|
353 QVariant HbThemeListModel::data(const QModelIndex& index, int role) const |
|
354 { |
|
355 QVariant retVal = QVariant(); |
|
356 |
|
357 if (index.isValid()) { |
|
358 switch (role) { |
|
359 case Qt::DisplayRole: |
|
360 retVal = mThemeChangerPrivate->themeList.at(index.row()).name; |
|
361 break; |
|
362 |
|
363 case Qt::DecorationRole: |
|
364 retVal = mThemeChangerPrivate->themeList.at(index.row()).icon; |
|
365 break; |
|
366 |
|
367 case Qt::SizeHintRole: |
|
368 retVal = mThemeChangerPrivate->themeList.at(index.row()).icon.size(); |
|
369 break; |
|
370 case CpThemeChanger::PortraitPreviewRole: |
|
371 retVal = mThemeChangerPrivate->themeList.at(index.row()).portraitPreviewIcon; |
|
372 break; |
|
373 case CpThemeChanger::LandscapePreviewRole: |
|
374 retVal = mThemeChangerPrivate->themeList.at(index.row()).landscapePreviewIcon; |
|
375 |
|
376 default: |
|
377 // do nothing |
|
378 qt_noop(); |
|
379 } |
|
380 } |
|
381 |
|
382 return retVal; |
|
383 } |
|
384 |
|
385 /* |
|
386 Responds appropriately when the underlying data in the theme changer is modified. |
|
387 |
|
388 Unfortunately the directory watcher from QFileWatcher only says when something changed |
|
389 not what changed. Therefore the model is considered reset rather than having rows |
|
390 with dataChanged. |
|
391 */ |
|
392 void HbThemeListModel::themeListChanged() |
|
393 { |
|
394 beginResetModel(); |
|
395 |
|
396 mThemeChangerPrivate->themes(); |
|
397 |
|
398 endResetModel(); |
|
399 } |
|
400 |
|
401 // End of file |
|