1 /*****************************************************************************
2 * input_manager.cpp : Manage an input and interact with its GUI elements
3 ****************************************************************************
4 * Copyright (C) 2000-2005 the VideoLAN team
5 * $Id: wxwidgets.cpp 15731 2006-05-25 14:43:53Z zorglub $
7 * Authors: Clément Stenac <zorglub@videolan.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 #include <QApplication>
25 #include "playlist_model.hpp"
29 static int PlaylistChanged( vlc_object_t *, const char *,
30 vlc_value_t, vlc_value_t, void * );
31 static int PlaylistNext( vlc_object_t *, const char *,
32 vlc_value_t, vlc_value_t, void * );
33 static int ItemChanged( vlc_object_t *, const char *,
34 vlc_value_t, vlc_value_t, void * );
35 static int ItemAppended( vlc_object_t *p_this, const char *psz_variable,
36 vlc_value_t oval, vlc_value_t nval, void *param );
37 static int ItemDeleted( vlc_object_t *p_this, const char *psz_variable,
38 vlc_value_t oval, vlc_value_t nval, void *param );
41 /*************************************************************************
42 * Playlist item implementation
43 *************************************************************************/
45 PLItem::PLItem( int _i_id, int _i_input_id, PLItem *parent, PLModel *m)
48 i_id = _i_id; i_input_id = _i_input_id;
52 PLItem::PLItem( playlist_item_t * p_item, PLItem *parent, PLModel *m )
55 i_input_id = p_item->p_input->i_id;
65 void PLItem::insertChild( PLItem *item, int i_pos, bool signal )
69 model->beginInsertRows( model->index( this , 0 ), i_pos, i_pos );
70 children.append( item );
72 model->endInsertRows();
75 int PLItem::row() const
78 return parentItem->children.indexOf(const_cast<PLItem*>(this));
83 /*************************************************************************
84 * Playlist model implementation
85 *************************************************************************/
87 PLModel::PLModel( playlist_item_t * p_root, int i_depth, QObject *parent)
88 : QAbstractItemModel(parent)
90 rootItem = new PLItem( p_root, NULL, this );
92 i_items_to_append = 0;
93 b_need_update = false;
95 i_cached_input_id = -1;
106 void PLModel::addCallbacks()
108 /* Some global changes happened -> Rebuild all */
109 var_AddCallback( p_playlist, "intf-change", PlaylistChanged, this );
110 /* We went to the next item */
111 var_AddCallback( p_playlist, "playlist-current", PlaylistNext, this );
112 /* One item has been updated */
113 var_AddCallback( p_playlist, "item-change", ItemChanged, this );
114 var_AddCallback( p_playlist, "item-append", ItemAppended, this );
115 var_AddCallback( p_playlist, "item-deleted", ItemDeleted, this );
118 void PLModel::delCallbacks()
120 var_DelCallback( p_playlist, "item-change", ItemChanged, this );
121 var_DelCallback( p_playlist, "playlist-current", PlaylistNext, this );
122 var_DelCallback( p_playlist, "intf-change", PlaylistChanged, this );
123 var_DelCallback( p_playlist, "item-append", ItemAppended, this );
124 var_DelCallback( p_playlist, "item-deleted", ItemDeleted, this );
127 /****************** Base model mandatory implementations *****************/
129 QVariant PLModel::data(const QModelIndex &index, int role) const
131 if (!index.isValid())
133 if (role != Qt::DisplayRole)
136 PLItem *item = static_cast<PLItem*>(index.internalPointer());
137 return QVariant( item->columnString( index.column() ) );
140 Qt::ItemFlags PLModel::flags(const QModelIndex &index) const
142 if (!index.isValid())
143 return Qt::ItemIsEnabled;
145 return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
148 QVariant PLModel::headerData( int section, Qt::Orientation orientation,
151 if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
152 return QVariant( rootItem->columnString( section ) );
156 QModelIndex PLModel::index(int row, int column, const QModelIndex &parent)
160 if (!parent.isValid())
161 parentItem = rootItem;
163 parentItem = static_cast<PLItem*>(parent.internalPointer());
165 PLItem *childItem = parentItem->child(row);
167 return createIndex(row, column, childItem);
169 return QModelIndex();
172 /* Return the index of a given item */
173 QModelIndex PLModel::index( PLItem *item, int column ) const
175 if( !item ) return QModelIndex();
176 const PLItem *parent = item->parent();
178 return createIndex( parent->children.lastIndexOf( item ), column, item );
179 return QModelIndex();
182 QModelIndex PLModel::parent(const QModelIndex &index) const
184 if (!index.isValid())
185 return QModelIndex();
187 PLItem *childItem = static_cast<PLItem*>(index.internalPointer());
188 PLItem *parentItem = childItem->parent();
190 if (parentItem == rootItem)
191 return QModelIndex();
193 return createIndex(parentItem->row(), 0, parentItem);
196 int PLModel::columnCount( const QModelIndex &i) const
201 int PLModel::childrenCount(const QModelIndex &parent) const
203 return rowCount( parent );
206 int PLModel::rowCount(const QModelIndex &parent) const
210 if (!parent.isValid())
211 parentItem = rootItem;
213 parentItem = static_cast<PLItem*>(parent.internalPointer());
215 return parentItem->childCount();
218 /************************* Lookups *****************************/
220 PLItem *PLModel::FindById( PLItem *root, int i_id )
222 return FindInner( root, i_id, false );
225 PLItem *PLModel::FindByInput( PLItem *root, int i_id )
227 return FindInner( root, i_id, true );
230 #define CACHE( i, p ) i_cached_id = i; p_cached_item = p;
231 #define ICACHE( i, p ) i_cached_input_id = i; p_cached_item_bi = p;
233 PLItem * PLModel::FindInner( PLItem *root, int i_id, bool b_input )
235 if( ( !b_input && i_cached_id == i_id) ||
236 ( b_input && i_cached_input_id ==i_id ) )
237 return b_input ? p_cached_item_bi : p_cached_item;
239 if( !b_input && root->i_id == i_id )
244 else if( b_input && root->i_input_id == i_id )
246 ICACHE( i_id, root );
250 QList<PLItem *>::iterator it = root->children.begin();
251 while ( it != root->children.end() )
253 if( !b_input && (*it)->i_id == i_id )
255 CACHE( i_id, (*it) );
256 return p_cached_item;
258 else if( b_input && (*it)->i_input_id == i_id )
260 ICACHE( i_id, (*it) );
262 if( (*it)->children.size() )
264 PLItem *childFound = FindInner( (*it), i_id, b_input );
269 ICACHE( i_id, childFound );
273 CACHE( i_id, childFound );
285 /************************* Updates handling *****************************/
286 void PLModel::customEvent( QEvent *event )
288 PLEvent *ple = dynamic_cast<PLEvent *>(event);
290 if( event->type() == ItemUpdate_Type )
291 ProcessInputItemUpdate( ple->i_id );
292 else if( event->type() == ItemAppend_Type )
293 ProcessItemAppend( ple->p_add );
295 ProcessItemRemoval( ple->i_id );
298 /**** Events processing ****/
299 void PLModel::ProcessInputItemUpdate( int i_input_id )
301 assert( i_input_id >= 0 );
302 UpdateTreeItem( FindByInput( rootItem, i_input_id ), true );
305 void PLModel::ProcessItemRemoval( int i_id )
308 if( i_id == i_cached_id ) i_cached_id = -1;
309 i_cached_input_id = -1;
314 void PLModel::ProcessItemAppend( playlist_add_t *p_add )
316 playlist_item_t *p_item = NULL;
318 if( b_need_update ) return;
320 PLItem *nodeItem = FindById( rootItem, p_add->i_node );
321 if( !nodeItem ) goto end;
323 p_item = playlist_ItemGetById( p_playlist, p_add->i_item );
324 if( !p_item || p_item->i_flags & PLAYLIST_DBL_FLAG ) goto end;
326 nodeItem->appendChild( new PLItem( p_item, nodeItem, this ) );
332 void PLModel::Rebuild()
334 /* Remove callbacks before locking to avoid deadlocks */
338 /* Invalidate cache */
339 i_cached_id = i_cached_input_id = -1;
342 qDeleteAll( rootItem->children );
344 /* Recreate from root */
345 UpdateNodeChildren( rootItem );
347 /* And signal the view */
348 emit layoutChanged();
354 void PLModel::UpdateNodeChildren( PLItem *root )
356 playlist_item_t *p_node = playlist_ItemGetById( p_playlist, root->i_id );
357 UpdateNodeChildren( p_node, root );
360 void PLModel::UpdateNodeChildren( playlist_item_t *p_node, PLItem *root )
362 for( int i = 0; i < p_node->i_children ; i++ )
364 PLItem *newItem = new PLItem( p_node->pp_children[i], root, this );
365 root->appendChild( newItem, false );
366 UpdateTreeItem( newItem, false );
367 if( p_node->pp_children[i]->i_children != -1 )
368 UpdateNodeChildren( p_node->pp_children[i], newItem );
372 void PLModel::UpdateTreeItem( PLItem *item, bool signal )
374 playlist_item_t *p_item = playlist_ItemGetById( p_playlist, rootItem->i_id );
375 UpdateTreeItem( p_item, item, signal );
378 void PLModel::UpdateTreeItem( playlist_item_t *p_item, PLItem *item, bool signal )
386 /**********************************************************************
388 **********************************************************************/
389 static int PlaylistChanged( vlc_object_t *p_this, const char *psz_variable,
390 vlc_value_t oval, vlc_value_t nval, void *param )
392 PLModel *p_model = (PLModel *) param;
393 p_model->b_need_update = VLC_TRUE;
397 static int PlaylistNext( vlc_object_t *p_this, const char *psz_variable,
398 vlc_value_t oval, vlc_value_t nval, void *param )
400 PLModel *p_model = (PLModel *) param;
401 PLEvent *event = new PLEvent( ItemUpdate_Type, oval.i_int );
402 QApplication::postEvent( p_model, static_cast<QEvent*>(event) );
403 event = new PLEvent( ItemUpdate_Type, nval.i_int );
404 QApplication::postEvent( p_model, static_cast<QEvent*>(event) );
408 static int ItemChanged( vlc_object_t *p_this, const char *psz_variable,
409 vlc_value_t oval, vlc_value_t nval, void *param )
411 PLModel *p_model = (PLModel *) param;
412 PLEvent *event = new PLEvent( ItemUpdate_Type, nval.i_int );
413 QApplication::postEvent( p_model, static_cast<QEvent*>(event) );
417 static int ItemDeleted( vlc_object_t *p_this, const char *psz_variable,
418 vlc_value_t oval, vlc_value_t nval, void *param )
420 PLModel *p_model = (PLModel *) param;
421 PLEvent *event = new PLEvent( ItemDelete_Type, nval.i_int );
422 QApplication::postEvent( p_model, static_cast<QEvent*>(event) );
426 static int ItemAppended( vlc_object_t *p_this, const char *psz_variable,
427 vlc_value_t oval, vlc_value_t nval, void *param )
429 PLModel *p_model = (PLModel *) param;
430 playlist_add_t *p_add = (playlist_add_t *)malloc( sizeof( playlist_add_t));
431 memcpy( p_add, nval.p_address, sizeof( playlist_add_t ) );
433 if( ++p_model->i_items_to_append >= 50 )
435 p_model->b_need_update = VLC_TRUE;
438 PLEvent *event = new PLEvent( p_add );
439 QApplication::postEvent( p_model, static_cast<QEvent*>(event) );