|
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 <QBrush> |
|
19 #include <QColor> |
|
20 #include <QtCore> |
|
21 |
|
22 #include <hbicon.h> |
|
23 #include <hbnamespace.h> |
|
24 #include <hgwidgets/hgwidgets.h> |
|
25 |
|
26 #include "hgwidgettestdatamodel.h" |
|
27 #include "hgwidgettestalbumartmanager.h" |
|
28 #include "trace.h" |
|
29 |
|
30 typedef QPair<int, int> Range; |
|
31 typedef QList<Range > RangeList; |
|
32 |
|
33 /*! |
|
34 \class HgWidgetTestDataModel |
|
35 \brief Music Player collection data model. |
|
36 |
|
37 Collection data model implements the interface specified by HbAbstractDataModel, |
|
38 which defines the standard interface that item models must use to be able to |
|
39 interoperate with other components in the model/view architecture. |
|
40 |
|
41 Every item of data that can be accessed via a model has an associated model |
|
42 index. |
|
43 |
|
44 Each item has a number of data elements associated with it and they can be |
|
45 retrieved by specifying a role (see Qt::ItemDataRole) to the model's data |
|
46 returned by itemData() function. |
|
47 |
|
48 \sa HbAbstractDataModel |
|
49 */ |
|
50 |
|
51 /*! |
|
52 Constructs the collection data model. |
|
53 */ |
|
54 HgWidgetTestDataModel::HgWidgetTestDataModel(QObject *parent) |
|
55 : QAbstractListModel(parent), |
|
56 mCachingInProgress(false), |
|
57 mImageType(TypeQImage), |
|
58 mDefaultIcon((":/images/default.svg")), |
|
59 mUseLowResImages(false) |
|
60 { |
|
61 FUNC_LOG; |
|
62 |
|
63 mAlbumArtManager = new HgWidgetTestAlbumArtManager; |
|
64 connect( mAlbumArtManager, SIGNAL(albumArtReady(int)), this, SLOT(updateAlbumArt(int)) ); |
|
65 connect( mAlbumArtManager, SIGNAL(albumCacheReady()), this, SLOT(albumCacheReady()) ); |
|
66 init(); |
|
67 } |
|
68 |
|
69 /*! |
|
70 Destructs the collection data model. |
|
71 */ |
|
72 HgWidgetTestDataModel::~HgWidgetTestDataModel() |
|
73 { |
|
74 FUNC_LOG; |
|
75 |
|
76 disconnect( mAlbumArtManager, SIGNAL(albumArtReady(int)), this, SLOT(updateAlbumArt(int)) ); |
|
77 disconnect( mAlbumArtManager, SIGNAL(albumCacheReady()), this, SLOT(albumCacheReady()) ); |
|
78 delete mAlbumArtManager; |
|
79 } |
|
80 |
|
81 void HgWidgetTestDataModel::setThumbnailSize(ThumbnailManager::ThumbnailSize size) |
|
82 { |
|
83 mAlbumArtManager->setThumbnailSize(size); |
|
84 } |
|
85 |
|
86 void HgWidgetTestDataModel::init() |
|
87 { |
|
88 FUNC_LOG; |
|
89 |
|
90 // Read all .jpg image paths from the c:/data/images folder |
|
91 QDir dir; |
|
92 dir.setFilter(QDir::Files | QDir:: Dirs); |
|
93 #ifdef __WINS__ |
|
94 dir.setPath(QString("c:/data/images")); |
|
95 #else |
|
96 dir.setPath(QString("f:/data/images")); |
|
97 #endif |
|
98 |
|
99 QFileInfoList list = dir.entryInfoList(); |
|
100 for (int i = 0; i < list.size(); ++i){ |
|
101 QFileInfo fileInfo = list.at(i); |
|
102 if (fileInfo.isFile()){ |
|
103 QString s = fileInfo.filePath(); |
|
104 if (s.indexOf(QString(".jpg"),0,Qt::CaseInsensitive)>0){ |
|
105 mFiles.append(s); |
|
106 mVisibility.append(true); |
|
107 } |
|
108 } |
|
109 } |
|
110 |
|
111 QPixmap pixmap(":/images/default.svg"); |
|
112 if (!pixmap.isNull()){ |
|
113 mQIcon = QIcon(pixmap); |
|
114 if (!mQIcon.isNull()){ |
|
115 mHbIcon = HbIcon(mQIcon); |
|
116 } |
|
117 } |
|
118 } |
|
119 |
|
120 /*! |
|
121 Returns the number of rows under the given \a parent. |
|
122 |
|
123 View will request for the row count immediately after a model is set. |
|
124 To prevent it from reading data while caching the album art for the first |
|
125 screen, return row count as zero. |
|
126 |
|
127 \reimp |
|
128 */ |
|
129 int HgWidgetTestDataModel::rowCount( const QModelIndex &parent ) const |
|
130 { |
|
131 Q_UNUSED(parent); |
|
132 return mFiles.count(); |
|
133 } |
|
134 |
|
135 /*! |
|
136 Returns the data stored for the item referred to by the \a index. |
|
137 |
|
138 \reimp |
|
139 */ |
|
140 QVariant HgWidgetTestDataModel::data(const QModelIndex &index, int role) const |
|
141 { |
|
142 QVariant returnValue = QVariant(); |
|
143 if ( !index.isValid() ) { |
|
144 return returnValue; |
|
145 } |
|
146 |
|
147 int row = index.row(); |
|
148 |
|
149 if( row >= mFiles.count() ){ |
|
150 return returnValue; |
|
151 } |
|
152 |
|
153 switch ( role ) |
|
154 { |
|
155 case HgWidget::HgVisibilityRole: |
|
156 { |
|
157 returnValue = mVisibility[index.row()]; |
|
158 } break; |
|
159 case Qt::DisplayRole: |
|
160 { |
|
161 QStringList texts; |
|
162 QString text( "Primary " ); |
|
163 text.append(QString::number(row)); |
|
164 texts << text; |
|
165 text = "Secondary "; |
|
166 text.append(QString::number(row)); |
|
167 texts << text; |
|
168 returnValue = texts; |
|
169 break; |
|
170 } |
|
171 case Qt::DecorationRole: |
|
172 { |
|
173 // INFO("Requesting model item" << row << ", " << mFiles.at(row)); |
|
174 if (mFiles.at(row).isEmpty()) { |
|
175 returnValue = mDefaultIcon; |
|
176 } |
|
177 else { |
|
178 QImage icon = mAlbumArtManager->albumArt(mFiles.at(row), row); |
|
179 if ( !icon.isNull() ) |
|
180 { |
|
181 if (mUseLowResImages) { |
|
182 QSize size = icon.size(); |
|
183 icon = icon.scaled(QSize(size.width()/4, size.height()/4)); |
|
184 } |
|
185 |
|
186 switch(mImageType) |
|
187 { |
|
188 case TypeHbIcon: |
|
189 { |
|
190 returnValue = mHbIcon; |
|
191 break; |
|
192 } |
|
193 case TypeQImage: |
|
194 { |
|
195 returnValue = icon; |
|
196 break; |
|
197 } |
|
198 case TypeQIcon: |
|
199 { |
|
200 returnValue = mQIcon; |
|
201 break; |
|
202 } |
|
203 default: |
|
204 break; |
|
205 } |
|
206 |
|
207 } |
|
208 else |
|
209 { |
|
210 returnValue = mDefaultIcon; |
|
211 } |
|
212 } |
|
213 break; |
|
214 } |
|
215 case Hb::IndexFeedbackRole: |
|
216 { |
|
217 returnValue = QString::number(row); |
|
218 break; |
|
219 } |
|
220 case Qt::BackgroundRole: |
|
221 { |
|
222 if ( (index.row() % 2) == 0 ) { |
|
223 QColor color(211,211,211,127); |
|
224 QBrush brush(color); |
|
225 returnValue = brush; |
|
226 } |
|
227 else { |
|
228 QColor color(255,250,250,127); |
|
229 QBrush brush(color); |
|
230 returnValue = brush; |
|
231 } |
|
232 break; |
|
233 } |
|
234 |
|
235 case (Qt::UserRole+2): |
|
236 { |
|
237 QImage icon = mAlbumArtManager->albumArt(mFiles.at(row), row); |
|
238 if (!icon.isNull()) |
|
239 { |
|
240 returnValue = icon; |
|
241 } |
|
242 } break; |
|
243 } |
|
244 |
|
245 return returnValue; |
|
246 } |
|
247 |
|
248 /*! |
|
249 Must be called when data has changed and model needs to be refreshed |
|
250 to reflect the new data. |
|
251 */ |
|
252 void HgWidgetTestDataModel::refreshModel() |
|
253 { |
|
254 // Cancel all outstanding album art request first, then reset the model. |
|
255 mAlbumArtManager->cancel(); |
|
256 |
|
257 // Before providing the new data to the view (list, grid, etc.), we want |
|
258 // to make sure that we have enough album arts for the first screen. |
|
259 /* mFiles.count() = mCollectionData->count(); |
|
260 if ( mFiles.count() > 0 ) { |
|
261 int initCount = ( mFiles.count() > KInitCacheSize ) ? KInitCacheSize : mFiles.count(); |
|
262 QStringList albumArtList; |
|
263 QString albumArtUri; |
|
264 for ( int i = 0; i < initCount; i++ ) { |
|
265 albumArtUri = mCollectionData->itemData(i, MpMpxCollectionData::AlbumArtUri); |
|
266 if ( !albumArtUri.isEmpty() ) { |
|
267 albumArtList << albumArtUri; |
|
268 } |
|
269 } |
|
270 mCachingInProgress = mAlbumArtManager->cacheAlbumArt(albumArtList); |
|
271 if ( !mCachingInProgress ) { |
|
272 reset(); |
|
273 } |
|
274 } |
|
275 else { |
|
276 reset(); |
|
277 } |
|
278 */ |
|
279 } |
|
280 |
|
281 /*! |
|
282 Remove items from model (do not actually delete them). |
|
283 */ |
|
284 void HgWidgetTestDataModel::remove(const QItemSelection &selection) |
|
285 { |
|
286 FUNC_LOG; |
|
287 |
|
288 QModelIndexList modelIndexes = selection.indexes(); |
|
289 int removeCount = modelIndexes.count(); |
|
290 int originalItemCount = mFiles.count(); |
|
291 if (originalItemCount-removeCount > 0) { |
|
292 RangeList removeRanges; |
|
293 qSort(modelIndexes); |
|
294 while (!modelIndexes.isEmpty()) { |
|
295 QModelIndexList::iterator i = modelIndexes.begin(); |
|
296 QModelIndexList::iterator start = i; |
|
297 int lastRow = i->row(); |
|
298 while (++i != modelIndexes.end() && i->row() == lastRow+1) { |
|
299 lastRow++; |
|
300 } |
|
301 removeRanges.append(Range(start->row(), lastRow)); |
|
302 modelIndexes.erase(start, i); |
|
303 } |
|
304 |
|
305 // Work backwards to keep the indexes consistent |
|
306 for (int i = removeRanges.count()-1; i >= 0; i--) { |
|
307 Range range = removeRanges.at(i); |
|
308 beginRemoveRows(QModelIndex(), range.first, range.second); |
|
309 for (int j = range.second; j >= range.first; j--) { |
|
310 INFO("Removing model item" << j); |
|
311 mFiles.removeAt(j); |
|
312 } |
|
313 endRemoveRows(); |
|
314 } |
|
315 } |
|
316 else if (originalItemCount-removeCount == 0) { |
|
317 beginRemoveRows(QModelIndex(), 0, originalItemCount-1); |
|
318 mFiles.clear(); |
|
319 endRemoveRows(); |
|
320 } |
|
321 } |
|
322 |
|
323 /*! |
|
324 Move items to the target index in the model. The selection should be contiguous. |
|
325 */ |
|
326 void HgWidgetTestDataModel::move(const QItemSelection &selection, const QModelIndex &target) |
|
327 { |
|
328 FUNC_LOG; |
|
329 |
|
330 QModelIndexList modelIndexes = selection.indexes(); |
|
331 |
|
332 if (modelIndexes.count() > 0 && target.isValid()) { |
|
333 int first = modelIndexes.front().row(); |
|
334 int last = modelIndexes.back().row(); |
|
335 int targetRow = target.row(); |
|
336 INFO("Move indexes" << first << "-" << last << "to" << targetRow); |
|
337 if (targetRow < first) { |
|
338 beginMoveRows(QModelIndex(), first, last, QModelIndex(), targetRow); |
|
339 for (int i = 0; i <= last-first; i++) { |
|
340 mFiles.move(first+i, targetRow+i); |
|
341 } |
|
342 endMoveRows(); |
|
343 } |
|
344 else if (targetRow > last) { |
|
345 beginMoveRows(QModelIndex(), first, last, QModelIndex(), targetRow); |
|
346 for (int i = 0; i <= last-first; i++) { |
|
347 mFiles.move(last-i, targetRow); |
|
348 } |
|
349 endMoveRows(); |
|
350 } |
|
351 } |
|
352 } |
|
353 |
|
354 /*! |
|
355 Add count dummy items at the target index in the model. |
|
356 */ |
|
357 void HgWidgetTestDataModel::add(const QModelIndex &target, int count) |
|
358 { |
|
359 FUNC_LOG; |
|
360 |
|
361 if (target.isValid()) { |
|
362 beginInsertRows(QModelIndex(), target.row(), target.row()+count-1); |
|
363 for (int i = 0; i < count; i++) { |
|
364 mFiles.insert(target.row(), QString()); |
|
365 mVisibility.insert(target.row(), true); |
|
366 } |
|
367 endInsertRows(); |
|
368 } |
|
369 } |
|
370 |
|
371 /*! |
|
372 Slot to be called when album art for the \a index needs to be updated. |
|
373 */ |
|
374 void HgWidgetTestDataModel::updateAlbumArt( int index ) |
|
375 { |
|
376 if ( index >= 0 && index < mFiles.count() ) { |
|
377 QModelIndex modelIndex = QAbstractItemModel::createIndex(index, 0); |
|
378 emit dataChanged(modelIndex, modelIndex); |
|
379 } |
|
380 } |
|
381 |
|
382 /*! |
|
383 Slot to be called when album art cache is ready. |
|
384 */ |
|
385 void HgWidgetTestDataModel::albumCacheReady() |
|
386 { |
|
387 if ( mCachingInProgress ) { |
|
388 mCachingInProgress = false; |
|
389 reset(); |
|
390 } |
|
391 } |
|
392 |
|
393 void HgWidgetTestDataModel::setImageDataType(ImageType type) |
|
394 { |
|
395 mImageType = type; |
|
396 } |
|
397 |
|
398 bool HgWidgetTestDataModel::setData(const QModelIndex& index, const QVariant& value, int role) |
|
399 { |
|
400 if (role == HgWidget::HgVisibilityRole) |
|
401 { |
|
402 mVisibility[index.row()] = value.toBool(); |
|
403 emit dataChanged(index, index); |
|
404 return true; |
|
405 } |
|
406 return false; |
|
407 } |
|
408 |
|
409 void HgWidgetTestDataModel::enableLowResImages(bool enabled) { |
|
410 |
|
411 mUseLowResImages = enabled; |
|
412 } |
|
413 |
|
414 bool HgWidgetTestDataModel::lowResImagesEnabled() const { |
|
415 |
|
416 return mUseLowResImages; |
|
417 } |
|
418 |