]> git.sur5r.net Git - minitube/blob - src/ListModel.cpp
Initial import
[minitube] / src / ListModel.cpp
1 #include "ListModel.h"
2 #include "videomimedata.h"
3
4 #define MAX_ITEMS 10
5
6 ListModel::ListModel(QWidget *parent) : QAbstractListModel(parent) {
7     youtubeSearch = 0;
8     searching = false;
9     canSearchMore = true;
10     m_activeVideo = 0;
11     m_activeRow = -1;
12     skip = 1;
13 }
14
15 ListModel::~ListModel() {
16     delete youtubeSearch;
17 }
18
19 int ListModel::rowCount(const QModelIndex &/*parent*/) const {
20     int count = videos.size();
21     
22     // add the message item
23     if (videos.isEmpty() || !searching)
24         count++;
25     
26     return count;
27 }
28
29 QVariant ListModel::data(const QModelIndex &index, int role) const {
30     
31     int row = index.row();
32     
33     if (row == videos.size()) {
34         
35         QPalette palette;
36         QFont boldFont;
37         boldFont.setBold(true);
38         
39         switch (role) {
40         case ItemTypeRole:
41             return ItemTypeShowMore;
42         case Qt::DisplayRole:
43         case Qt::StatusTipRole:
44             if (searching) return tr("Searching...");
45             if (canSearchMore) return tr("Show %1 More").arg(MAX_ITEMS);
46             if (videos.isEmpty()) return tr("No videos");
47             else return tr("No more videos");
48         case Qt::TextAlignmentRole:
49             return QVariant(int(Qt::AlignHCenter | Qt::AlignVCenter));
50         case Qt::ForegroundRole:
51             return palette.color(QPalette::Dark);
52         case Qt::FontRole:
53             return boldFont;
54         default:
55             return QVariant();
56         }
57         
58     } else if (row < 0 || row >= videos.size())
59         return QVariant();
60     
61     Video *video = videos.at(row);
62     
63     switch (role) {
64     case ItemTypeRole:
65         return ItemTypeVideo;
66     case VideoRole:
67         return QVariant::fromValue(QPointer<Video>(video));
68     case ActiveTrackRole:
69         return video == m_activeVideo;
70     case Qt::DisplayRole:
71     case Qt::StatusTipRole:
72         return video->title();
73         /*
74         case Qt::ToolTipRole:
75           
76             QString tooltip;
77             if (!element.firstChildElement().text().isEmpty()) {
78                 tooltip.append(QString("<b>").append(element.firstChildElement().text()).append("</b><br/>"));
79             }
80             if (!fromDate.isEmpty()) {
81                 tooltip.append("<i>Pubblicato il</i> ").append(fromDate);
82             }
83             if (!toDate.isEmpty()) {
84                 tooltip.append("<br/><i>Scadenza</i>: ").append(toDate);
85             }
86             tooltip.append("<br/><i>Tipo</i>: ").append(typeName)
87                 .append("<br/><i>Id</i>: ").appen    QFont boldFont;
88     boldFont.setBold(true);d(id);
89             return tooltip;
90             */
91         
92          case StreamUrlRole:
93         return video->streamUrl();
94     }
95     
96     return QVariant();
97 }
98
99 void ListModel::setActiveRow( int row) {
100     if ( rowExists( row ) ) {
101         
102         m_activeRow = row;
103         m_activeVideo = videoAt(row);
104         
105         // setStateOfRow( row, Item::Played );
106         
107         int oldactiverow = m_activeRow;
108         
109         if ( rowExists( oldactiverow ) )
110             emit dataChanged( createIndex( oldactiverow, 0 ), createIndex( oldactiverow, columnCount() - 1 ) );
111         
112         emit dataChanged( createIndex( m_activeRow, 0 ), createIndex( m_activeRow, columnCount() - 1 ) );
113         emit activeRowChanged(row);
114         
115     } else {
116         m_activeRow = -1;
117         m_activeVideo = 0;
118     }
119
120 }
121
122 int ListModel::nextRow() const {
123     int nextRow = m_activeRow + 1;
124     if (rowExists(nextRow))
125         return nextRow;
126     return -1;
127 }
128
129 Video* ListModel::videoAt( int row ) const {
130     if ( rowExists( row ) )
131         return videos.at( row );
132     return 0;
133 }
134
135 Video* ListModel::activeVideo() const {
136     return m_activeVideo;
137 }
138
139 void ListModel::search(SearchParams *searchParams) {
140
141     // delete current videos
142     while (!videos.isEmpty())
143         delete videos.takeFirst();
144     m_activeVideo = 0;
145     m_activeRow = -1;
146     skip = 1;
147     reset();
148
149     // (re)initialize the YouTubeSearch
150     if (youtubeSearch) delete youtubeSearch;
151     youtubeSearch = new YouTubeSearch();
152     connect(youtubeSearch, SIGNAL(gotVideo(Video*)), this, SLOT(addVideo(Video*)));
153     connect(youtubeSearch, SIGNAL(finished(int)), this, SLOT(searchFinished(int)));
154
155     this->searchParams = searchParams;
156     searching = true;
157     youtubeSearch->search(searchParams, MAX_ITEMS, skip);
158     skip += MAX_ITEMS;
159 }
160
161 void ListModel::searchMore(int max) {
162     if (searching) return;
163     searching = true;
164     youtubeSearch->search(searchParams, max, skip);
165     skip += max;
166 }
167
168 void ListModel::searchMore() {
169     searchMore(MAX_ITEMS);
170 }
171
172 void ListModel::searchNeeded() {
173     int remainingRows = videos.size() - m_activeRow;
174     int rowsNeeded = MAX_ITEMS - remainingRows;
175     if (rowsNeeded > 0)
176         searchMore(rowsNeeded);
177 }
178
179 void ListModel::abortSearch() {
180     while (!videos.isEmpty())
181         delete videos.takeFirst();
182     reset();
183     youtubeSearch->abort();
184     searching = false;
185 }
186
187 void ListModel::searchFinished(int total) {
188     searching = false;
189     canSearchMore = total > 0;
190 }
191
192 void ListModel::addVideo(Video* video) {
193     
194     connect(video, SIGNAL(gotThumbnail()), this, SLOT(updateThumbnail()));
195
196     beginInsertRows(QModelIndex(), videos.size(), videos.size());
197     videos << video;
198     endInsertRows();
199     
200     // autoplay
201     if (videos.size() == 1) {
202         setActiveRow(0);
203     }
204
205 }
206
207 void ListModel::updateThumbnail() {
208
209     Video *video = static_cast<Video *>(sender());
210     if (!video) {
211         qDebug() << "Cannot get sender";
212         return;
213     }
214
215     int row = rowForVideo(video);
216     emit dataChanged( createIndex( row, 0 ), createIndex( row, columnCount() - 1 ) );
217
218 }
219
220 // --- item removal
221
222 /**
223   * This function does not free memory
224   */
225 bool ListModel::removeRows(int position, int rows, const QModelIndex & /*parent*/) {
226     beginRemoveRows(QModelIndex(), position, position+rows-1);
227     for (int row = 0; row < rows; ++row) {
228         videos.removeAt(position);
229     }
230     endRemoveRows();
231     return true;
232 }
233
234 void ListModel::removeIndexes(QModelIndexList &indexes) {
235     QList<Video*> originalList(videos);
236     QList<Video*> delitems;
237     foreach (QModelIndex index, indexes) {
238         Video* video = originalList.at(index.row());
239         int idx = videos.indexOf(video);
240         if (idx != -1) {
241             beginRemoveRows(QModelIndex(), idx, idx);
242             delitems.append(video);
243             videos.removeAll(video);
244             endRemoveRows();
245         }
246     }
247
248     qDeleteAll(delitems);
249
250 }
251
252 // --- Sturm und drang ---
253
254
255
256 Qt::DropActions ListModel::supportedDropActions() const {
257     return Qt::MoveAction;
258 }
259
260 Qt::ItemFlags ListModel::flags(const QModelIndex &index) const {
261     Qt::ItemFlags defaultFlags = QAbstractListModel::flags(index);
262
263     if (index.isValid()) {
264         if (index.row() == videos.size()) {
265             // don't drag the "show 10 more" item
266             return defaultFlags;
267         } else
268             return ( defaultFlags | Qt::ItemIsDropEnabled | Qt::ItemIsDragEnabled );
269     } else
270         return Qt::ItemIsDropEnabled | defaultFlags;
271 }
272
273 QStringList ListModel::mimeTypes() const {
274     QStringList types;
275     types << "application/x-minitube-video";
276     return types;
277 }
278
279 QMimeData* ListModel::mimeData( const QModelIndexList &indexes ) const {
280     VideoMimeData* mime = new VideoMimeData();
281
282     foreach( const QModelIndex &it, indexes ) {
283         int row = it.row();
284         if (row >= 0 && row < videos.size())
285             mime->addVideo( videos.at( it.row() ) );
286     }
287
288     return mime;
289 }
290
291 bool ListModel::dropMimeData(const QMimeData *data,
292                              Qt::DropAction action, int row, int column,
293                              const QModelIndex &parent) {
294     if (action == Qt::IgnoreAction)
295         return true;
296
297     if (!data->hasFormat("application/x-minitube-video"))
298         return false;
299
300     if (column > 0)
301         return false;
302
303     int beginRow;
304     if (row != -1)
305         beginRow = row;
306     else if (parent.isValid())
307         beginRow = parent.row();
308     else
309         beginRow = rowCount(QModelIndex());
310
311     const VideoMimeData* videoMimeData = dynamic_cast<const VideoMimeData*>( data );
312     if(!videoMimeData ) return false;
313
314     QList<Video*> droppedVideos = videoMimeData->videos();
315     foreach( Video *video, droppedVideos) {
316         
317         // remove videos
318         int videoRow = videos.indexOf(video);
319         removeRows(videoRow, 1, QModelIndex());
320         
321         // and then add them again at the new position
322         beginInsertRows(QModelIndex(), beginRow, beginRow);
323         videos.insert(beginRow, video);
324         endInsertRows();
325
326     }
327
328     // fix m_activeRow after all this
329     m_activeRow = videos.indexOf(m_activeVideo);
330
331     // let the MediaView restore the selection
332     emit needSelectionFor(droppedVideos);
333
334     return true;
335
336 }
337
338 int ListModel::rowForVideo(Video* video) {
339     return videos.indexOf(video);
340 }
341
342 QModelIndex ListModel::indexForVideo(Video* video) {
343     return createIndex(videos.indexOf(video), 0);
344 }
345
346 void ListModel::move(QModelIndexList &indexes, bool up) {
347
348     QList<Video*> movedVideos;
349
350     foreach (QModelIndex index, indexes) {
351         int row = index.row();
352         qDebug() << "index row" << row;
353         Video *video = videoAt(row);
354         movedVideos << video;
355     }
356
357     int counter = 1;
358     foreach (Video *video, movedVideos) {
359
360         int row = rowForVideo(video);
361         qDebug() << "video row" << row;
362         removeRows(row, 1, QModelIndex());
363
364         if (up) row--;
365         else row++;
366
367         beginInsertRows(QModelIndex(), row, row);
368         videos.insert(row, video);
369         endInsertRows();
370
371         counter++;
372     }
373
374     emit needSelectionFor(movedVideos);
375
376 }