ML Model/Item which queries the module and provides a QAbstractItemModel Interface
components/epg/EPGWidget.moc.cpp \
components/playlist/views.moc.cpp \
components/playlist/vlc_model.moc.cpp \
+ components/playlist/ml_item.moc.cpp \
+ components/playlist/ml_model.moc.cpp \
components/playlist/playlist_model.moc.cpp \
components/playlist/playlist.moc.cpp \
components/playlist/standardpanel.moc.cpp \
components/epg/EPGView.cpp \
components/epg/EPGWidget.cpp \
components/playlist/views.cpp \
+ components/playlist/ml_item.cpp \
+ components/playlist/ml_model.cpp \
components/playlist/vlc_model.cpp \
components/playlist/playlist_model.cpp \
components/playlist/playlist_item.cpp \
components/epg/EPGView.hpp \
components/epg/EPGWidget.hpp \
components/playlist/views.hpp \
+ components/playlist/ml_item.hpp \
+ components/playlist/ml_model.hpp \
components/playlist/vlc_model.hpp \
components/playlist/playlist_model.hpp \
components/playlist/playlist_item.hpp \
--- /dev/null
+/*****************************************************************************
+ * ml_item.cpp: the media library's result item
+ *****************************************************************************
+ * Copyright (C) 2008-2011 the VideoLAN Team and AUTHORS
+ * $Id$
+ *
+ * Authors: Antoine Lejeune <phytos@videolan.org>
+ * Jean-Philippe André <jpeg@videolan.org>
+ * Rémi Duraffort <ivoire@videolan.org>
+ * Adrien Maglo <magsoft@videolan.org>
+ * Srikanth Raju <srikiraju#gmail#com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef MEDIA_LIBRARY
+
+#include <QDateTime>
+#include <QUrl>
+#include <QFileInfo>
+#include "ml_item.hpp"
+#include <assert.h>
+
+
+/**
+ * @brief Compare the attribute 'meta' between medias a and b.
+ * @param a
+ * @param b
+ * @param meta
+ * @note If a->meta < b->meta, return -1
+ * If a->meta == b->meta, return 0
+ * If a->meta > b->meta, return +1
+ * @note If a->meta == NULL and b->meta != NULL (strings), then b>a
+ */
+static int compareMeta( const ml_media_t *a, const ml_media_t *b,
+ ml_select_e meta )
+{
+# define scomp(c) ((a->c&&b->c&&*a->c&&*b->c) ? strcasecmp(a->c,b->c) : \
+ (a->c&&*a->c?-1:(b->c&&*b->c?1:0)))
+# define icomp(c) (a->c<b->c?-1:(a->c==b->c?0:1))
+ switch( meta )
+ {
+ case ML_ALBUM: return scomp( psz_album );
+ case ML_ALBUM_ID: return icomp( i_album_id );
+ //case ML_ARTIST: return scomp( psz_artist );
+ //case ML_ARTIST_ID: return icomp( i_artist_id );
+ case ML_COVER: return scomp( psz_cover );
+ case ML_DURATION: return icomp( i_duration );
+ case ML_EXTRA: return scomp( psz_extra );
+ case ML_GENRE: return scomp( psz_genre );
+ case ML_ID: return icomp( i_id );
+ case ML_LAST_PLAYED: return icomp( i_last_played );
+ case ML_ORIGINAL_TITLE: return scomp( psz_orig_title );
+ case ML_PLAYED_COUNT: return icomp( i_played_count );
+ // case ML_ROLE: return 0;
+ case ML_SCORE: return icomp( i_score );
+ case ML_TITLE: return scomp( psz_title );
+ case ML_TRACK_NUMBER: return icomp( i_track_number );
+ case ML_TYPE: return icomp( i_type );
+ case ML_URI: return scomp( psz_uri );
+ case ML_VOTE: return icomp( i_vote );
+ case ML_YEAR: return icomp( i_year );
+ default: return 0;
+ }
+# undef scomp
+# undef icomp
+}
+
+
+MLItem::MLItem( const MLModel *p_model,
+ intf_thread_t* _p_intf,
+ ml_media_t *p_media,
+ MLItem *p_parent )
+ : model( p_model ), children(), parentItem( p_parent ), p_intf( _p_intf )
+{
+ if( p_media )
+ ml_gc_incref( p_media );
+ this->media = p_media;
+ p_ml = ml_Hold( _p_intf );
+}
+
+MLItem::~MLItem()
+{
+ // Free private data
+ if( this->media )
+ ml_gc_decref( this->media );
+ ml_Release( p_intf );
+ if( !children.isEmpty() )
+ clearChildren();
+}
+
+/**
+ * @brief recursively delete all children of this node
+ * @note must be entered after the appropriate beginRemoveRows()
+ */
+void MLItem::clearChildren()
+{
+ // Recursively delete all children
+ qDeleteAll( children );
+ children.clear();
+}
+
+MLItem* MLItem::child( int row ) const
+{
+ if( row < 0 || row >= childCount() ) return NULL;
+ else return children.at( row );
+}
+
+void MLItem::addChild( MLItem *child, int row )
+{
+ assert( child );
+ children.insert( row==-1 ? children.size() : row, child );
+}
+
+void MLItem::delChild( int row )
+{
+ if( !childCount() ) return; // assert ?
+ MLItem *item =
+ children.takeAt( ( row!=-1 ) ? row : ( children.size()-1 ) );
+ assert( item );
+ delete item;
+}
+
+int MLItem::rowOfChild( MLItem *item ) const
+{
+ return children.indexOf( item );
+}
+
+int MLItem::childCount() const
+{
+ return children.size();
+}
+
+MLItem* MLItem::parent() const
+{
+ return parentItem;
+}
+
+/**
+ * @brief Get a QVariant representing the data on a column
+ * @param column
+ * @return The QVariant may be formed of a int, QString
+ * Use toString() to print it on the screen, except for pixmaps
+ */
+QVariant MLItem::data( int column ) const
+{
+ ml_select_e type = model->columnType( column );
+ ml_person_t *p_people = NULL, *p_person = NULL;
+ QString qsz_return;
+#define sreturn(a) if(media->a) return qfu(media->a); break
+ switch( type )
+ {
+ case ML_ALBUM: sreturn( psz_album );
+ case ML_ALBUM_ID: return media->i_album_id;
+ case ML_ARTIST:
+ p_people = ml_GetPersonsFromMedia( p_ml, media, ML_PERSON_ARTIST );
+ p_person = p_people;
+ while( p_person )
+ {
+ if( !EMPTY_STR( p_person->psz_name ) )
+ {
+ qsz_return.isEmpty() ? qsz_return = qfu( p_person->psz_name ) :
+ qsz_return.append( "," ).append( qfu( p_person->psz_name ) );
+ }
+ p_person = p_person->p_next;
+ }
+ ml_FreePeople( p_people );
+ return qsz_return;
+ break;
+ case ML_COVER: sreturn( psz_cover );
+ case ML_DURATION:
+ return QTime().addSecs( media->i_duration/1000000 ).toString( "HH:mm:ss" );
+ case ML_EXTRA: sreturn( psz_extra );
+ case ML_GENRE: sreturn( psz_genre );
+ case ML_ID: return media->i_id;
+ case ML_LAST_PLAYED:
+ {
+ if( media->i_last_played > 0 )
+ {
+ QDateTime time( QDate(1970,1,1) );
+ return time.addSecs( qint64( media->i_last_played ) );
+ }
+ else
+ return QString();
+ }
+ case ML_ORIGINAL_TITLE: sreturn( psz_orig_title );
+ case ML_PLAYED_COUNT: return media->i_played_count;
+ // case ML_ROLE: return qtr( "Role" );
+ case ML_SCORE: return media->i_score ? media->i_score : QVariant();
+ case ML_TITLE:
+ {
+ /* If no title, return filename */
+ if( !EMPTY_STR( media->psz_title ) )
+ return qfu( media->psz_title );
+ else
+ {
+ QFileInfo p_file = QFileInfo( qfu( media->psz_uri ) );
+ return p_file.fileName().isEmpty() ? p_file.absoluteFilePath()
+ : p_file.fileName();
+ }
+ }
+ case ML_TRACK_NUMBER: return media->i_track_number ? media->i_track_number : QVariant();
+ case ML_TYPE:
+ {
+ QString txt;
+ if( media->i_type & ML_AUDIO )
+ txt = "Audio";
+ if( media->i_type & ML_VIDEO )
+ txt = "Video";
+ if( media->i_type & ML_STREAM )
+ {
+ if( txt.isEmpty() ) txt = "Stream";
+ else txt += " stream";
+ }
+ if( media->i_type & ML_REMOVABLE )
+ {
+ if( txt.isEmpty() ) txt = "Removable media";
+ else txt += " (removable media)";
+ }
+ if( media->i_type & ML_NODE )
+ {
+ if( txt.isEmpty() ) txt = "Playlist";
+ else txt += " (Playlist)";
+ }
+ if( txt.isEmpty() )
+ txt = qtr( "Unknown" );
+ return txt;
+ }
+ case ML_URI: sreturn( psz_uri );
+ case ML_VOTE: return media->i_vote ? media->i_vote : QVariant();
+ case ML_YEAR: return media->i_year ? media->i_year : QVariant();
+ default: return QVariant();
+ }
+# undef sreturn
+ return QVariant();
+}
+
+bool MLItem::setData( ml_select_e meta, const QVariant &data )
+{
+# define setmeta(a) ml_LockMedia(media); free(media->a); \
+ media->a = strdup( qtu(data.toString()) ); ml_UnlockMedia( media ); \
+ goto update;
+ switch( meta )
+ {
+ /* String values */
+ case ML_ALBUM: setmeta( psz_album );
+ case ML_ARTIST: ml_DeletePersonTypeFromMedia( media, ML_PERSON_ARTIST );
+ ml_CreateAppendPersonAdv( &media->p_people,
+ ML_PERSON_ARTIST, (char*)qtu(data.toString()), 0 );
+ return ml_UpdateSimple( p_ml, ML_MEDIA, NULL, id(),
+ ML_PEOPLE, ML_PERSON_ARTIST, qtu( data.toString() ) ) == VLC_SUCCESS;
+ case ML_EXTRA: setmeta( psz_extra );
+ case ML_GENRE: setmeta( psz_genre );
+ case ML_ORIGINAL_TITLE: setmeta( psz_orig_title );
+ case ML_TITLE: setmeta( psz_title );
+update:
+ return ml_UpdateSimple( p_ml, ML_MEDIA, NULL, id(),
+ meta, qtu( data.toString() ) ) == VLC_SUCCESS;
+
+ /* Modifiable integers */
+ case ML_TRACK_NUMBER:
+ case ML_YEAR:
+ return ml_UpdateSimple( p_ml, ML_MEDIA, NULL, id(),
+ meta, data.toInt() ) == VLC_SUCCESS;
+
+ // TODO case ML_VOTE:
+
+ /* Non modifiable meta */
+ default:
+ return false;
+ }
+# undef setmeta
+}
+
+int MLItem::id() const
+{
+ return media->i_id;
+}
+
+ml_media_t* MLItem::getMedia() const
+{
+ return media;
+}
+
+QUrl MLItem::getUri() const
+{
+ if( !media->psz_uri ) return QUrl(); // This should be rootItem
+ QString uri = qfu( media->psz_uri );
+ if( uri.contains( "://" ) )
+ return QUrl( uri );
+ else
+ return QUrl( "file://" + uri );
+}
+
+bool MLItem::operator<( MLItem* item )
+{
+ int ret = compareMeta( getMedia(), item->getMedia(), ML_ALBUM );
+ if( ret == -1 )
+ return true;
+ else return false;
+}
+#endif
--- /dev/null
+/*****************************************************************************
+ * ml_item.hpp: the media library's result item
+ *****************************************************************************
+ * Copyright (C) 2008-2011 the VideoLAN Team and AUTHORS
+ * $Id$
+ *
+ * Authors: Antoine Lejeune <phytos@videolan.org>
+ * Jean-Philippe André <jpeg@videolan.org>
+ * Rémi Duraffort <ivoire@videolan.org>
+ * Adrien Maglo <magsoft@videolan.org>
+ * Srikanth Raju <srikiraju#gmail#com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifndef _MEDIA_LIBRARY_MLITEM_H
+#define _MEDIA_LIBRARY_MLITEM_H
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef MEDIA_LIBRARY
+
+#include <vlc_common.h>
+#include <vlc_interface.h>
+#include <vlc_media_library.h>
+
+#include "ml_model.hpp"
+#include "qt4.hpp"
+
+class MLModel;
+
+class MLItem
+{
+public:
+ MLItem( const MLModel *p_model, intf_thread_t *_p_intf,
+ ml_media_t *p_media, MLItem *p_parent );
+ virtual ~MLItem();
+
+ void addChild( MLItem *child, int row = -1 );
+ void delChild( int row );
+ void clearChildren();
+
+ MLItem* child( int row ) const;
+ int childCount() const;
+
+ MLItem* parent() const;
+
+ QVariant data( int column ) const;
+ bool setData( ml_select_e meta, const QVariant &data );
+
+ int rowOfChild( MLItem *item ) const;
+
+ // Media structure connections
+ int id() const;
+ ml_media_t* getMedia() const;
+ QUrl getUri() const;
+
+ bool operator<( MLItem* item );
+
+private:
+ ml_media_t* media;
+ intf_thread_t* p_intf;
+ media_library_t* p_ml;
+ QList< MLItem* > children;
+ MLItem *parentItem;
+ const MLModel *model;
+};
+
+#endif
+#endif
--- /dev/null
+/*****************************************************************************
+ * ml_model.cpp: the media library's model
+ *****************************************************************************
+ * Copyright (C) 2008-2011 the VideoLAN Team and AUTHORS
+ * $Id$
+ *
+ * Authors: Antoine Lejeune <phytos@videolan.org>
+ * Jean-Philippe André <jpeg@videolan.org>
+ * Rémi Duraffort <ivoire@videolan.org>
+ * Adrien Maglo <magsoft@videolan.org>
+ * Srikanth Raju <srikiraju#gmail#com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef MEDIA_LIBRARY
+
+#include <QUrl>
+#include <QMenu>
+#include <QMimeData>
+#include "ml_item.hpp"
+#include "ml_model.hpp"
+#include "dialogs/mediainfo.hpp"
+#include "dialogs/playlist.hpp"
+#include "components/playlist/sorting.h"
+#include "dialogs_provider.hpp"
+#include "input_manager.hpp" /* THEMIM */
+
+#include <assert.h>
+#include <vlc_intf_strings.h>
+
+static int mediaAdded( vlc_object_t *p_this, char const *psz_var,
+ vlc_value_t oldval, vlc_value_t newval,
+ void *data );
+static int mediaDeleted( vlc_object_t *p_this, char const *psz_var,
+ vlc_value_t oldval, vlc_value_t newval,
+ void *data );
+static int mediaUpdated( vlc_object_t *p_this, char const *psz_var,
+ vlc_value_t oldval, vlc_value_t newval,
+ void *data );
+
+/**
+ * @brief Definition of the result item model for the result tree
+ * @param parent the parent Qt object
+ */
+MLModel::MLModel( intf_thread_t* _p_intf, QObject *parent )
+ :VLCModel( _p_intf, parent )
+{
+ p_ml = ml_Hold( p_intf );
+ vlc_array_t *p_result_array = vlc_array_new();
+ ml_Find( p_ml, p_result_array, ML_MEDIA );
+ insertResultArray( p_result_array );
+
+ var_AddCallback( p_ml, "media-added", mediaAdded, this );
+ var_AddCallback( p_ml, "media-deleted", mediaDeleted, this );
+ var_AddCallback( p_ml, "media-meta-change", mediaUpdated, this );
+}
+
+/**
+ * @brief Simple destructor for the model
+ */
+MLModel::~MLModel()
+{
+ var_DelCallback( p_ml, "media-meta-change", mediaUpdated, this );
+ var_DelCallback( p_ml, "media-deleted", mediaDeleted, this );
+ var_DelCallback( p_ml, "media-added", mediaAdded, this );
+ ml_Release( p_intf );
+}
+
+void MLModel::clear()
+{
+ int rows = rowCount();
+ if( rows > 0 )
+ {
+ beginRemoveRows( createIndex( 0, 0 ), 0, rows-1 );
+ items.clear();
+ endRemoveRows();
+ emit layoutChanged();
+ }
+}
+
+QModelIndex MLModel::index( int row, int column,
+ const QModelIndex &parent ) const
+{
+ if( parent.isValid() )
+ return QModelIndex();
+ else
+ {
+ QModelIndex idx = createIndex( row, column, items.value( row ) );
+ return idx;
+ }
+}
+
+QModelIndex MLModel::parent(const QModelIndex &index) const
+{
+ return QModelIndex();
+}
+
+/**
+ * @brief Return the index of currently playing item
+ */
+QModelIndex MLModel::currentIndex() const
+{
+ input_thread_t *p_input_thread = THEMIM->getInput();
+ if( !p_input_thread ) return QModelIndex();
+
+ /*TODO: O(n) not good */
+ input_item_t* p_iitem = input_GetItem( p_input_thread );
+ foreach( MLItem* item, items )
+ {
+ if( !QString::compare( item->getUri().toString(),
+ QString::fromAscii( p_iitem->psz_uri ) ) )
+ return index( items.indexOf( item ), 0 );
+ }
+ return QModelIndex();
+}
+/**
+ * @brief This returns the type of data shown in the specified column
+ * @param column must be valid
+ * @return The type, or ML_END in case of error
+ */
+ml_select_e MLModel::columnType( int logicalindex ) const
+{
+ if( logicalindex < 0 || logicalindex >= columnCount() ) return ML_END;
+ return meta_to_mlmeta( columnToMeta( logicalindex ) );
+}
+
+QVariant MLModel::headerData( int section, Qt::Orientation orientation,
+ int role ) const
+{
+ if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
+ return QVariant( psz_column_title( columnToMeta( section ) ) );
+ else
+ return QVariant();
+}
+
+Qt::ItemFlags MLModel::flags(const QModelIndex &index) const
+{
+ if( !index.isValid() )
+ return 0;
+
+ if( isEditable( index ) )
+ return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled
+ | Qt::ItemIsEditable;
+ else
+ return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled;
+}
+
+bool MLModel::isEditable( const QModelIndex &index ) const
+{
+ if( !index.isValid() )
+ return false;
+
+ ml_select_e type = columnType( index.column() );
+ switch( type )
+ {
+ // Read-only members: not editable
+ case ML_ALBUM_ID:
+ case ML_ARTIST_ID:
+ case ML_DURATION:
+ case ML_ID:
+ case ML_LAST_PLAYED:
+ case ML_PLAYED_COUNT:
+ case ML_TYPE:
+ return false;
+ // Read-write members: editable
+ case ML_ALBUM:
+ case ML_ARTIST:
+ case ML_COVER:
+ case ML_EXTRA:
+ case ML_GENRE:
+ case ML_ORIGINAL_TITLE:
+ // case ML_ROLE:
+ case ML_SCORE:
+ case ML_TITLE:
+ case ML_TRACK_NUMBER:
+ case ML_URI:
+ case ML_VOTE:
+ case ML_YEAR:
+ return true;
+ }
+ return false;
+}
+
+QMimeData* MLModel::mimeData( const QModelIndexList &indexes ) const
+{
+ QList< QUrl > urls;
+ QList< int > rows;
+ foreach( QModelIndex idx, indexes )
+ {
+ if( rows.contains( idx.row() ) )
+ continue;
+ rows.append( idx.row() );
+ MLItem* item = static_cast<MLItem*>( idx.internalPointer() );
+ urls.append( item->getUri() );
+ }
+ QMimeData *data = new QMimeData;
+ data->setUrls( urls );
+ return data;
+}
+
+int MLModel::columnCount( const QModelIndex & parent ) const
+{
+ return columnFromMeta( COLUMN_END );
+}
+
+int MLModel::rowCount( const QModelIndex & parent ) const
+{
+ if( !parent.isValid() )
+ return items.count();
+ return 0;
+}
+
+void MLModel::remove( MLItem *item )
+{
+ int row = items.indexOf( item );
+ remove( createIndex( row, 0 ) );
+}
+
+void MLModel::remove( QModelIndexList list )
+{
+ for (int i = 0; i < list.size(); ++i) {
+ remove( list.at(i) );
+ }
+}
+
+void MLModel::remove( QModelIndex idx )
+{
+ if( !idx.isValid() )
+ return;
+ else
+ {
+ beginRemoveRows( createIndex( 0, 0 ), idx.row(), idx.row() );
+ items.removeAt( idx.row() );
+ endRemoveRows();
+ }
+}
+
+int MLModel::getId( QModelIndex index ) const
+{
+ return getItem( index )->id();
+}
+
+QVariant MLModel::data( const QModelIndex &index, int role ) const
+{
+ if( index.isValid() )
+ if( role == Qt::DisplayRole || role == Qt::EditRole )
+ {
+ MLItem *it = static_cast<MLItem*>( index.internalPointer() );
+ if( !it ) return QVariant();
+ QVariant tmp = it->data( index.column() );
+ return tmp;
+ }
+ else if( role == VLCModel::IsLeafNodeRole )
+ return QVariant( true );
+ else if( role == VLCModel::IsCurrentsParentNodeRole )
+ return QVariant( false );
+ return QVariant();
+}
+
+bool MLModel::setData( const QModelIndex &idx, const QVariant &value,
+ int role )
+{
+ if( role != Qt::EditRole || !idx.isValid() ) return false;
+ MLItem *media = static_cast<MLItem*>( idx.internalPointer() );
+ media->setData( columnType( idx.column() ), value );
+ emit dataChanged( idx, idx );
+}
+
+/**
+ * @brief Insert a media to the model in a given row
+ * @param p_media the media to append
+ * @param row the future row for this media, -1 to append at the end
+ * @param bSignal signal Qt that the model has been modified,
+ * should NOT be used by the user
+ * @return a VLC error code
+ */
+int MLModel::insertMedia( ml_media_t *p_media, int row,
+ bool bSignal )
+{
+ // Some checks
+ if( !p_media || row < -1 || row > rowCount() )
+ return VLC_EGENERIC;
+
+ if( row == -1 )
+ row = rowCount();
+
+ if( bSignal )
+ beginInsertRows( createIndex( -1, -1 ), row, row );
+
+ // Create and insert the item
+ MLItem *item = new MLItem( this, p_intf, p_media, NULL );
+ items.append( item );
+
+ if( bSignal )
+ endInsertRows();
+
+ return VLC_SUCCESS;
+}
+
+/**
+ * @brief Append a media to the model
+ * @param p_media the media to append
+ * @return see insertMedia
+ * @note Always signals. Do not use in a loop.
+ */
+int MLModel::appendMedia( ml_media_t *p_media )
+{
+ return insertMedia( p_media, -1, true );
+}
+
+/**
+ * @brief Insert all medias from an array to the model
+ * @param p_media_array the medias to append
+ * @return see insertMedia
+ * @note if bSignal==true, then it signals only once
+ */
+int MLModel::insertMediaArray( vlc_array_t *p_media_array,
+ int row, bool bSignal )
+{
+ int i_ok = VLC_SUCCESS;
+ int count = vlc_array_count( p_media_array );
+
+ if( !count )
+ return i_ok;
+
+ if( row == -1 )
+ row = rowCount();
+
+ // Signal Qt that we will insert rows
+ if( bSignal )
+ beginInsertRows( createIndex( -1, -1 ), row, row + count-1 );
+
+ // Loop
+ for( int i = 0; i < count; ++i )
+ {
+ i_ok = insertMedia( (ml_media_t*)
+ vlc_array_item_at_index( p_media_array, i ), row + i, false );
+ if( i_ok != VLC_SUCCESS )
+ break;
+ }
+
+ if( bSignal )
+ endInsertRows();
+
+ return i_ok;
+}
+
+/**
+ * @brief Insert the media contained in a result to the model
+ * @param p_result the media to append is p_result->value.p_media
+ * @param row the future row for this media
+ * @param bSignal signal Qt that the model has been modified,
+ * should NOT be used by the user
+ * @return a VLC error code
+ */
+int MLModel::insertResult( const ml_result_t *p_result, int row,
+ bool bSignal )
+{
+ if( !p_result || p_result->type != ML_TYPE_MEDIA )
+ return VLC_EGENERIC;
+ else
+ return insertMedia( p_result->value.p_media, row, bSignal );
+}
+
+/**
+ * @brief Append the media contained in a result to the model
+ * @param p_result the media to append is p_result->value.p_media
+ * @param row the future row for this media
+ * @return a VLC error code
+ * @note Always signals. Do not use in a loop.
+ */
+inline int MLModel::appendResult( const ml_result_t *p_result )
+{
+ return insertResult( p_result, -1, true );
+}
+
+/**
+ * @brief Insert all medias from a result array to the model
+ * @param p_result_array the medias to append
+ * @return see insertMedia
+ * @note if bSignal==true, then it signals only once
+ * not media or NULL items are skipped
+ */
+int MLModel::insertResultArray( vlc_array_t *p_result_array,
+ int row, bool bSignal )
+{
+ int i_ok = VLC_SUCCESS;
+ int count = vlc_array_count( p_result_array );
+
+ if( !count )
+ return i_ok;
+
+ if( row == -1 )
+ row = rowCount();
+
+ // Signal Qt that we will insert rows
+ if( bSignal )
+ beginInsertRows( createIndex( -1, -1 ), row, row + count-1 );
+
+ // Loop and insert
+ for( int i = 0; i < count; ++i )
+ {
+ ml_result_t *p_result = (ml_result_t*)
+ vlc_array_item_at_index( p_result_array, i );
+ if( !p_result || p_result->type != ML_TYPE_MEDIA )
+ continue;
+ i_ok = insertMedia( p_result->value.p_media, row + i, false );
+ if( i_ok != VLC_SUCCESS )
+ break;
+ }
+ // Signal we're done
+ if( bSignal )
+ endInsertRows();
+
+ return i_ok;
+}
+
+/** **************************************************************************
+ * \brief Add a media to the playlist
+ *
+ * \param id the item id
+ * @todo this code must definitely be done by the ML core
+ *****************************************************************************/
+static void AddItemToPlaylist( int i_media_id, bool bPlay, media_library_t* p_ml,
+ bool bRenew )
+{
+
+ input_item_t *p_item = ml_CreateInputItem( p_ml, i_media_id );
+ if( !p_item )
+ {
+ msg_Dbg( p_ml, "unable to create input item for media %d",
+ i_media_id );
+ return;
+ }
+ playlist_t *p_playlist = pl_Get( p_ml );
+ playlist_item_t *p_playlist_item = NULL;
+
+ playlist_Lock( p_playlist );
+ if( !bRenew )
+ {
+ p_playlist_item = playlist_ItemGetByInput( p_playlist, p_item );
+ }
+
+ if( !p_playlist_item || p_playlist_item->i_id == 1 )
+ {
+ playlist_AddInput( p_playlist, p_item,
+ PLAYLIST_APPEND,
+ PLAYLIST_END, true, true );
+
+ p_playlist_item = playlist_ItemGetByInput( p_playlist, p_item );
+ }
+ playlist_Unlock( p_playlist );
+
+ if( !p_playlist_item || p_playlist_item->i_id == 1 )
+ {
+ msg_Dbg( p_ml, "could not find playlist item %s (%s:%d)",
+ p_item->psz_name, __FILE__, __LINE__ );
+ return;
+ }
+
+ /* Auto play item */
+ if( bPlay ) // || p_playlist->status.i_status == PLAYLIST_STOPPED )
+ {
+ playlist_Control( p_playlist, PLAYLIST_VIEWPLAY, false,
+ NULL, p_playlist_item );
+ }
+ vlc_gc_decref( p_item );
+}
+
+void MLModel::activateItem( const QModelIndex &index )
+{
+ play( index );
+}
+
+void MLModel::play( const QModelIndex &idx )
+{
+ if( !idx.isValid() )
+ return;
+ MLItem *item = static_cast< MLItem* >( idx.internalPointer() );
+ if( !item )
+ return;
+ AddItemToPlaylist( item->id(), true, p_ml, true );
+}
+
+bool MLModel::popup( const QModelIndex & index, const QPoint &point, const QModelIndexList &list )
+{
+ current_selection = list;
+ current_index = index;
+ QMenu menu;
+ if( index.isValid() )
+ {
+ menu.addAction( QIcon( ":/menu/play" ), qtr(I_POP_PLAY), this, SLOT( popupPlay() ) );
+ menu.addAction( QIcon( ":/menu/stream" ),
+ qtr(I_POP_STREAM), this, SLOT( popupStream() ) );
+ menu.addAction( qtr(I_POP_SAVE), this, SLOT( popupSave() ) );
+ menu.addAction( QIcon( ":/menu/info" ), qtr(I_POP_INFO), this, SLOT( popupInfo() ) );
+ menu.addSeparator();
+ }
+
+
+ QIcon addIcon( ":/buttons/playlist/playlist_add" );
+ menu.addSeparator();
+ menu.addAction( addIcon, qtr(I_PL_ADDF), THEDP, SLOT( simpleMLAppendDialog()) );
+ menu.addAction( addIcon, qtr(I_PL_ADDDIR), THEDP, SLOT( MLAppendDir() ) );
+ menu.addAction( addIcon, qtr(I_OP_ADVOP), THEDP, SLOT( MLAppendDialog() ) );
+
+ if( index.isValid() )
+ {
+ menu.addAction( QIcon( ":/buttons/playlist/playlist_remove" ),
+ qtr(I_POP_DEL), this, SLOT( popupDel() ) );
+ menu.addSeparator();
+ }
+ if( !menu.isEmpty() )
+ {
+ menu.exec( point ); return true;
+ }
+ else return false;
+}
+
+
+void MLModel::popupDel()
+{
+ remove( current_selection );
+}
+
+void MLModel::popupPlay()
+{
+ play( current_index );
+}
+
+void MLModel::popupInfo()
+{
+ MLItem *item = static_cast< MLItem* >( current_index.internalPointer() );
+ input_item_t* p_input = ml_CreateInputItem( p_ml, item->id() );
+ MediaInfoDialog *mid = new MediaInfoDialog( p_intf, p_input );
+ mid->setParent( PlaylistDialog::getInstance( p_intf ),
+ Qt::Dialog );
+ mid->show();
+}
+
+QStringList MLModel::selectedURIs()
+{
+ QStringList list;
+ for( int i = 0; i < current_selection.size(); i++ )
+ {
+ QModelIndex idx = current_selection.value(i);
+ MLItem *item = static_cast< MLItem* >( idx.internalPointer() );
+ list.append( QString( item->getUri().toString() ) );
+ }
+ return list;
+}
+
+void MLModel::popupStream()
+{
+ QStringList mrls = selectedURIs();
+ if( !mrls.isEmpty() )
+ THEDP->streamingDialog( NULL, mrls[0], false );
+
+}
+
+void MLModel::popupSave()
+{
+ QStringList mrls = selectedURIs();
+ if( !mrls.isEmpty() )
+ THEDP->streamingDialog( NULL, mrls[0] );
+}
+
+static int mediaAdded( vlc_object_t *p_this, char const *psz_var,
+ vlc_value_t oldval, vlc_value_t newval,
+ void *data )
+{
+ int ret = VLC_SUCCESS;
+ media_library_t *p_ml = ( media_library_t* )p_this;
+ MLModel* p_model = ( MLModel* )data;
+ vlc_array_t* p_result = vlc_array_new();
+ ret = ml_FindMedia( p_ml, p_result, ML_ID, newval.i_int );
+ if( ret != VLC_SUCCESS )
+ {
+ vlc_array_destroy( p_result );
+ return VLC_EGENERIC;
+ }
+ p_model->insertResultArray( p_result );
+ vlc_array_destroy( p_result );
+ return VLC_SUCCESS;
+}
+
+static int mediaDeleted( vlc_object_t *p_this, char const *psz_var,
+ vlc_value_t oldval, vlc_value_t newval,
+ void *data )
+{
+ MLModel* p_model = ( MLModel* )data;
+ QModelIndex remove_idx = QModelIndex();
+ for( int i = 0; i < p_model->rowCount( ); i++ )
+ {
+ QModelIndex idx = p_model->index( i, 0 );
+ MLItem *item = static_cast< MLItem* >( idx.internalPointer() );
+ if( item->id() == newval.i_int )
+ {
+ remove_idx = idx;
+ break;
+ }
+ }
+ if( remove_idx.isValid() )
+ p_model->remove( remove_idx );
+ return VLC_SUCCESS;
+}
+
+static int mediaUpdated( vlc_object_t *p_this, char const *psz_var,
+ vlc_value_t oldval, vlc_value_t newval,
+ void *data )
+{
+ return VLC_SUCCESS;
+}
+
+#endif
--- /dev/null
+/*****************************************************************************
+ * ml_model.hpp ML model
+ *****************************************************************************
+ * Copyright (C) 2008-2011 the VideoLAN Team and AUTHORS
+ * $Id$
+ *
+ * Authors: Antoine Lejeune <phytos@videolan.org>
+ * Jean-Philippe André <jpeg@videolan.org>
+ * Rémi Duraffort <ivoire@videolan.org>
+ * Adrien Maglo <magsoft@videolan.org>
+ * Srikanth Raju <srikiraju#gmail#com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifndef _MEDIA_LIBRARY_MLMODEL_H
+#define _MEDIA_LIBRARY_MLMODEL_H
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef MEDIA_LIBRARY
+#include <vlc_common.h>
+#include <vlc_interface.h>
+#include <vlc_media_library.h>
+
+#include "components/playlist/vlc_model.hpp"
+#include "ml_item.hpp"
+#include "qt4.hpp"
+
+class MLItem;
+
+/** *************************************************************************
+ * \brief Tree model for the result list
+ ****************************************************************************/
+class MLModel : public VLCModel
+{
+ Q_OBJECT;
+
+public:
+ // Basic QAbstractItemModel implementation
+ MLModel( intf_thread_t *_p_intf, QObject *parent = NULL );
+ virtual ~MLModel();
+ inline MLItem *getItem( QModelIndex index ) const
+ {
+ if( index.isValid() )
+ return static_cast<MLItem*>( index.internalPointer() );
+ else return NULL;
+ }
+ virtual int getId( QModelIndex index ) const;
+
+ QVariant data( const QModelIndex &idx, int role = Qt::DisplayRole ) const;
+ bool setData( const QModelIndex &idx, const QVariant &value,
+ int role = Qt::EditRole );
+ ml_select_e columnType( int column ) const;
+
+ QModelIndex index( int row, int column,
+ const QModelIndex & parent = QModelIndex() ) const;
+ virtual QModelIndex currentIndex() const;
+ int rowCount( const QModelIndex & parent = QModelIndex() ) const;
+ int columnCount( const QModelIndex & parent = QModelIndex() ) const;
+
+ QModelIndex parent( const QModelIndex& ) const;
+ QVariant headerData( int, Qt::Orientation, int ) const;
+ Qt::ItemFlags flags( const QModelIndex& ) const;
+ bool isEditable( const QModelIndex& ) const;
+
+ // Drag and drop: MIME data
+ QMimeData* mimeData( const QModelIndexList & indexes ) const;
+
+ // Custom functions
+ int insertMedia( ml_media_t *p_media, int row = -1,
+ bool bSignal = true );
+ int appendMedia( ml_media_t *p_media );
+ int insertMediaArray( vlc_array_t *p_media_array, int row = -1,
+ bool bSignal = true );
+
+ int insertResult( const ml_result_t *p_result, int row = -1,
+ bool bSignal = true );
+ inline int appendResult( const ml_result_t *p_result );
+ int insertResultArray( vlc_array_t *p_result_array, int row = -1,
+ bool bSignal = true );
+
+ void remove( MLItem *item );
+ void remove( QModelIndexList list );
+ void remove( QModelIndex idx );
+
+ void clear();
+ virtual bool popup( const QModelIndex & index, const QPoint &point, const QModelIndexList &list );
+ void play( const QModelIndex &idx );
+ QStringList selectedURIs();
+
+public slots:
+ void activateItem( const QModelIndex &index );
+
+protected slots:
+ void popupDel();
+ void popupPlay();
+ void popupInfo();
+ void popupStream();
+ void popupSave();
+
+private:
+ QList< MLItem* > items;
+ media_library_t* p_ml;
+
+ QModelIndex current_index;
+ QModelIndexList current_selection;
+};
+
+#endif
+#endif
/*****************************************************************************
* sorting.h : commun sorting & column display code
****************************************************************************
- * Copyright © 2008 the VideoLAN team
+ * Copyright © 2008 the VideoLAN team and AUTHORS
* $Id$
*
* Authors: Rafaël Carré <funman@videolanorg>
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
+#ifndef _SORTING_H_
+#define _SORTING_H_
+#include <vlc_media_library.h>
/* You can use these numbers with | and & to determine what you want to show */
enum
{
COLUMN_DESCRIPTION = 0x0040,
COLUMN_URI = 0x0080,
COLUMN_NUMBER = 0x0100,
+ COLUMN_RATING = 0x0200,
+ COLUMN_COVER = 0x0400,
/* Add new entries here and update the COLUMN_END value*/
- COLUMN_END = 0x0200
+ COLUMN_END = 0x0800
};
#define COLUMN_DEFAULT (COLUMN_TITLE|COLUMN_DURATION|COLUMN_ALBUM)
case COLUMN_TRACK_NUMBER: return VLC_META_TRACK_NUMBER;
case COLUMN_DESCRIPTION: return VLC_META_DESCRIPTION;
case COLUMN_URI: return _("URI");
+ case COLUMN_RATING: return VLC_META_RATING;
+ case COLUMN_COVER: return VLC_META_ART_URL;
default: abort();
}
}
return input_item_GetDescription( p_item );
case COLUMN_URI:
return input_item_GetURI( p_item );
+ case COLUMN_RATING:
+ return input_item_GetRating( p_item );
+ case COLUMN_COVER:
+ return input_item_GetArtworkURL( p_item );
default:
abort();
}
case COLUMN_TRACK_NUMBER: return SORT_TRACK_NUMBER;
case COLUMN_DESCRIPTION: return SORT_DESCRIPTION;
case COLUMN_URI: return SORT_URI;
+ case COLUMN_RATING: return SORT_RATING;
default: abort();
}
}
+
+static inline ml_select_e meta_to_mlmeta( uint32_t i_column )
+{
+ switch( i_column )
+ {
+ case COLUMN_NUMBER: return ML_ID;
+ case COLUMN_TITLE: return ML_TITLE;
+ case COLUMN_DURATION: return ML_DURATION;
+ case COLUMN_ARTIST: return ML_ARTIST;
+ case COLUMN_GENRE: return ML_GENRE;
+ case COLUMN_ALBUM: return ML_ALBUM;
+ case COLUMN_TRACK_NUMBER: return ML_TRACK_NUMBER;
+ case COLUMN_DESCRIPTION: return ML_EXTRA;
+ case COLUMN_URI: return ML_URI;
+ case COLUMN_RATING: return ML_VOTE;
+ case COLUMN_COVER: return ML_COVER;
+ default: abort();
+ }
+}
+
+#endif