Commit ed89fe73 authored by Srikanth Raju's avatar Srikanth Raju

Qt/ML: ML Model and Item

ML Model/Item which queries the module and provides a QAbstractItemModel Interface
parent e51eb917
......@@ -60,6 +60,8 @@ nodist_SOURCES_qt4 = \
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 \
......@@ -276,6 +278,8 @@ SOURCES_qt4 = qt4.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 \
......@@ -343,6 +347,8 @@ noinst_HEADERS = \
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 \
......
/*****************************************************************************
* 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
/*****************************************************************************
* 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
/*****************************************************************************
* 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
/*****************************************************************************
* 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>
......@@ -21,6 +21,9 @@
* 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
{
......@@ -33,10 +36,12 @@ 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)
......@@ -55,6 +60,8 @@ static inline const char * psz_column_title( uint32_t i_column )
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();
}
}
......@@ -88,6 +95,10 @@ static inline char * psz_column_meta( input_item_t *p_item, uint32_t i_column )
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();
}
......@@ -107,6 +118,28 @@ static inline int i_column_sorting( uint32_t i_column )
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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment