]> git.sesse.net Git - vlc/blob - modules/gui/qt4/components/playlist/ml_item.cpp
aca7db1525ec9f3bf2455249ca09a794bce6ff67
[vlc] / modules / gui / qt4 / components / playlist / ml_item.cpp
1 /*****************************************************************************
2  * ml_item.cpp: the media library's result item
3  *****************************************************************************
4  * Copyright (C) 2008-2011 the VideoLAN Team and AUTHORS
5  * $Id$
6  *
7  * Authors: Antoine Lejeune <phytos@videolan.org>
8  *          Jean-Philippe André <jpeg@videolan.org>
9  *          Rémi Duraffort <ivoire@videolan.org>
10  *          Adrien Maglo <magsoft@videolan.org>
11  *          Srikanth Raju <srikiraju#gmail#com>
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26  *****************************************************************************/
27
28 #ifdef HAVE_CONFIG_H
29 # include <config.h>
30 #endif
31
32 #ifdef MEDIA_LIBRARY
33
34 #include <QDateTime>
35 #include <QUrl>
36 #include <QFileInfo>
37 #include "ml_item.hpp"
38 #include <assert.h>
39
40
41 /**
42  * @brief Compare the attribute 'meta' between medias a and b.
43  * @param a
44  * @param b
45  * @param meta
46  * @note If a->meta < b->meta, return -1
47  *       If a->meta == b->meta, return 0
48  *       If a->meta > b->meta, return +1
49  * @note If a->meta == NULL and b->meta != NULL (strings), then b>a
50  */
51 static int compareMeta( ml_media_t *a, ml_media_t *b, ml_select_e meta )
52 {
53     bool i_ret = 0;
54 #   define scomp(c) i_ret = ((a->c&&b->c&&*a->c&&*b->c) ?\
55                      strcasecmp(a->c,b->c) : \
56                      (a->c&&*a->c?-1:(b->c&&*b->c?1:0))); break;
57 #   define icomp(c) i_ret = (a->c<b->c?-1:(a->c==b->c?0:1)); break;
58     if ( a == b ) return 0;
59     vlc_mutex_lock( &a->lock );
60     vlc_mutex_lock( &b->lock );
61     switch( meta )
62     {
63     case ML_ALBUM: scomp( psz_album );
64     case ML_ALBUM_ID: icomp( i_album_id );
65         //case ML_ARTIST: scomp( psz_artist );
66         //case ML_ARTIST_ID: icomp( i_artist_id );
67     case ML_COVER: scomp( psz_cover );
68     case ML_DURATION: icomp( i_duration );
69     case ML_EXTRA: scomp( psz_extra );
70     case ML_GENRE: scomp( psz_genre );
71     case ML_ID: icomp( i_id );
72     case ML_LAST_PLAYED: icomp( i_last_played );
73     case ML_ORIGINAL_TITLE: scomp( psz_orig_title );
74     case ML_PLAYED_COUNT: icomp( i_played_count );
75         // case ML_ROLE:  0;
76     case ML_SCORE: icomp( i_score );
77     case ML_TITLE: scomp( psz_title );
78     case ML_TRACK_NUMBER: icomp( i_track_number );
79     case ML_TYPE: icomp( i_type );
80     case ML_URI: scomp( psz_uri );
81     case ML_VOTE: icomp( i_vote );
82     case ML_YEAR: icomp( i_year );
83     default:
84         break;
85     }
86 #   undef scomp
87 #   undef icomp
88     vlc_mutex_unlock( &a->lock );
89     vlc_mutex_unlock( &b->lock );
90     return i_ret;
91 }
92
93
94 MLItem::MLItem( intf_thread_t* _p_intf,
95                             ml_media_t *p_media,
96                             MLItem *p_parent )
97 {
98     parentItem = p_parent;
99     if( p_media )
100         ml_gc_incref( p_media );
101     media = p_media;
102     p_ml = ml_Get( _p_intf );
103 }
104
105 MLItem::~MLItem()
106 {
107     // Free private data
108     if( this->media )
109         ml_gc_decref( this->media );
110     if( !children.isEmpty() )
111         clearChildren();
112 }
113
114 AbstractPLItem* MLItem::child( int row ) const
115 {
116     if( row < 0 || row >= childCount() ) return NULL;
117     else return children.at( row );
118 }
119
120 input_item_t* MLItem::inputItem()
121 {
122     return ml_CreateInputItem( p_ml,  id( MLMEDIA_ID ) );
123 }
124
125 /**
126  * @brief Get a QVariant representing the data on a column
127  * @param column
128  * @return The QVariant may be formed of a int, QString
129  *         Use toString() to print it on the screen, except for pixmaps
130  */
131 QVariant MLItem::data( ml_select_e columntype ) const
132 {
133     ml_person_t *p_people = NULL, *p_person = NULL;
134     QVariant ret;
135     QString temp;
136
137 #define sget(a) if(media->a) ret = qfu(media->a);
138 #define iget(a) if(media->a) ret = QVariant(media->a);
139
140     vlc_mutex_lock( &media->lock );
141
142     switch( columntype )
143     {
144         case ML_ALBUM:
145             sget( psz_album );
146             break;
147         case ML_ALBUM_ID:
148             iget( i_album_id );
149             break;
150         case ML_ARTIST:
151             vlc_mutex_unlock( &media->lock );
152             p_people = ml_GetPersonsFromMedia( p_ml, media, ML_PERSON_ARTIST );
153             vlc_mutex_lock( &media->lock );
154             p_person = p_people;
155             while( p_person )
156             {
157                 if( !EMPTY_STR( p_person->psz_name ) )
158                 {
159                     temp.isEmpty() ? temp = qfu( p_person->psz_name ) :
160                         temp.append( "," ).append( qfu( p_person->psz_name ) );
161                 }
162                 p_person = p_person->p_next;
163             }
164             ml_FreePeople( p_people );
165             ret = temp;
166             break;
167         case ML_COVER:
168             sget( psz_cover );
169             break;
170         case ML_DURATION:
171             if ( media->i_duration )
172                 ret = QTime().addSecs( media->i_duration/1000000 ).toString( "HH:mm:ss" );
173             break;
174         case ML_EXTRA:
175             sget( psz_extra );
176             break;
177         case ML_GENRE:
178             sget( psz_genre );
179             break;
180         case ML_ID:
181             iget( i_id );
182             break;
183         case ML_LAST_PLAYED:
184             if( media->i_last_played > 0 )
185             {
186                 QDateTime time( QDate(1970,1,1) );
187                 ret = time.addSecs( qint64( media->i_last_played ) );
188             }
189             break;
190         case ML_ORIGINAL_TITLE:
191             sget( psz_orig_title );
192             break;
193         case ML_PLAYED_COUNT:
194             iget( i_played_count );
195             break;
196         // case ML_ROLE: return qtr( "Role" );
197         case ML_SCORE:
198             if ( media->i_score ) iget( i_score );
199             break;
200         case ML_TITLE:
201             temp = qfu( media->psz_title );
202             /* If no title, return filename */
203             if( temp.isEmpty() )
204             {
205                 vlc_mutex_unlock( &media->lock );
206                 QUrl uri = getURI();
207                 vlc_mutex_lock( &media->lock );
208                 if ( uri.scheme() != "file" )
209                     ret = QUrl::fromPercentEncoding( uri.toString().toUtf8() );
210
211                 QFileInfo p_file( uri.toLocalFile() );
212                 ret = p_file.fileName().isEmpty() ? p_file.absoluteFilePath()
213                     : p_file.fileName();
214             } else {
215                 ret = temp;
216             }
217             break;
218         case ML_TRACK_NUMBER:
219             if ( media->i_track_number ) iget( i_track_number );
220             break;
221         case ML_TYPE:
222             if( media->i_type & ML_AUDIO )
223                 temp = "Audio";
224             if( media->i_type & ML_VIDEO )
225                 temp = "Video";
226             if( media->i_type & ML_STREAM )
227             {
228                 if( temp.isEmpty() ) temp = "Stream";
229                 else temp += " stream";
230             }
231             if( media->i_type & ML_REMOVABLE )
232             {
233                 if( temp.isEmpty() ) temp = "Removable media";
234                 else temp += " (removable media)";
235             }
236             if( media->i_type & ML_NODE )
237             {
238                 if( temp.isEmpty() ) temp = "Playlist";
239                 else temp += " (Playlist)";
240             }
241             if( temp.isEmpty() )
242                 temp = qtr( "Unknown" );
243             ret = temp;
244             break;
245         case ML_URI:
246             sget( psz_uri );
247             break;
248         case ML_VOTE:
249             if ( media->i_vote ) iget( i_vote );
250             break;
251         case ML_YEAR:
252             if ( media->i_year ) iget( i_year );
253             break;
254         default:
255             break;
256     }
257
258     vlc_mutex_unlock( &media->lock );
259
260 #undef sget
261 #undef iget
262     return ret;
263 }
264
265 bool MLItem::setData( ml_select_e meta, const QVariant &data )
266 {
267 #   define setmeta(a) ml_LockMedia(media); free(media->a);                  \
268     media->a = strdup( qtu(data.toString()) ); ml_UnlockMedia( media );     \
269     goto update;
270     switch( meta )
271     {
272         /* String values */
273         case ML_ALBUM: setmeta( psz_album );
274         case ML_ARTIST: ml_DeletePersonTypeFromMedia( media, ML_PERSON_ARTIST );
275                         ml_CreateAppendPersonAdv( &media->p_people,
276                                 ML_PERSON_ARTIST, (char*)qtu(data.toString()), 0 );
277                         return ml_UpdateSimple( p_ml, ML_MEDIA, NULL, id( MLMEDIA_ID ),
278                                 ML_PEOPLE, ML_PERSON_ARTIST, qtu( data.toString() ) ) == VLC_SUCCESS;
279         case ML_EXTRA: setmeta( psz_extra );
280         case ML_GENRE: setmeta( psz_genre );
281         case ML_ORIGINAL_TITLE: setmeta( psz_orig_title );
282         case ML_TITLE: setmeta( psz_title );
283 update:
284         Q_ASSERT( qtu( data.toString() ) );
285             return ml_UpdateSimple( p_ml, ML_MEDIA, NULL, id( MLMEDIA_ID ),
286                                     meta, qtu( data.toString() ) ) == VLC_SUCCESS;
287
288         /* Modifiable integers */
289         case ML_TRACK_NUMBER:
290         case ML_YEAR:
291             return ml_UpdateSimple( p_ml, ML_MEDIA, NULL, id( MLMEDIA_ID ),
292                                     meta, data.toInt() ) == VLC_SUCCESS;
293
294         // TODO case ML_VOTE:
295
296         /* Non modifiable meta */
297         default:
298             return false;
299     }
300 #   undef setmeta
301 }
302
303 int MLItem::id( int type )
304 {
305     switch( type )
306     {
307     case INPUTITEM_ID:
308         return inputItem()->i_id;
309     case MLMEDIA_ID:
310         return media->i_id;
311     default:
312     case PLAYLIST_ID:
313         assert( NULL );
314         return -1;
315     }
316 }
317
318 ml_media_t* MLItem::getMedia() const
319 {
320     return media;
321 }
322
323 QUrl MLItem::getURI() const
324 {
325     QString uri;
326     vlc_mutex_lock( &media->lock );
327     uri = qfu( media->psz_uri );
328     vlc_mutex_unlock( &media->lock );
329     if ( uri.isEmpty() ) return QUrl(); // This should be rootItem
330
331     QUrl url = QUrl::fromEncoded( uri.toUtf8(), QUrl::TolerantMode );
332     if ( url.scheme().isEmpty() ) url.setScheme( "file" );
333     return url;
334 }
335
336 QString MLItem::getTitle() const
337 {
338     QString title;
339     vlc_mutex_lock( &media->lock );
340     title = QString( media->psz_title );
341     vlc_mutex_unlock( &media->lock );
342     return title;
343 }
344
345 bool MLItem::operator<( MLItem* item )
346 {
347      int ret = compareMeta( getMedia(), item->getMedia(), ML_ALBUM );
348      if( ret == -1 )
349          return true;
350      else return false;
351 }
352 #endif