playlistinfo.m 15.7 KB
Newer Older
Benjamin Pracht's avatar
Benjamin Pracht committed
1
/*****************************************************************************
2
 r playlistinfo.m: MacOS X interface module
Benjamin Pracht's avatar
Benjamin Pracht committed
3
 *****************************************************************************
4
 * Copyright (C) 2002-2006 the VideoLAN team
5
 * $Id$
Benjamin Pracht's avatar
Benjamin Pracht committed
6
 *
7
 * Authors: Benjamin Pracht <bigben at videolan dot org>
8
 *          Felix Kühne <fkuehne at videolan dot org>
Benjamin Pracht's avatar
Benjamin Pracht committed
9 10 11 12 13
 *
 * 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.
14
 *
Benjamin Pracht's avatar
Benjamin Pracht committed
15 16 17 18 19 20 21
 * 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
Antoine Cellerier's avatar
Antoine Cellerier committed
22
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
Benjamin Pracht's avatar
Benjamin Pracht committed
23 24 25 26 27 28 29 30 31 32 33 34 35 36
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/

#include "intf.h"
#include "playlistinfo.h"
#include "playlist.h"

/*****************************************************************************
 * VLCPlaylistInfo Implementation
 *****************************************************************************/

37 38 39 40 41 42 43 44
@implementation VLCInfo

- (id)init
{
    self = [super init];

    if( self != nil )
    {
45
        p_item = NULL;
46 47 48 49
    }
    return( self );
}

Benjamin Pracht's avatar
Benjamin Pracht committed
50 51 52 53
- (void)awakeFromNib
{
    [o_info_window setExcludedFromWindowsMenu: TRUE];

54
    [o_info_window setTitle: _NS("Information")];
Benjamin Pracht's avatar
Benjamin Pracht committed
55 56 57
    [o_uri_lbl setStringValue: _NS("URI")];
    [o_title_lbl setStringValue: _NS("Title")];
    [o_author_lbl setStringValue: _NS("Author")];
58 59
    [o_btn_ok setTitle: _NS("OK")];
    [o_btn_cancel setTitle: _NS("Cancel")];
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
    
    [[o_tab_view tabViewItemAtIndex: 0] setLabel: _NS("General")];
    [[o_tab_view tabViewItemAtIndex: 1] setLabel: _NS("Advanced Information")];
    [[o_tab_view tabViewItemAtIndex: 2] setLabel: _NS("Statistics")];
    [o_tab_view selectTabViewItemAtIndex: 0];

    /* constants defined in vlc_meta.h */
    [o_genre_lbl setStringValue: _NS(VLC_META_GENRE)];
    [o_copyright_lbl setStringValue: _NS(VLC_META_COPYRIGHT)];
    [o_collection_lbl setStringValue: _NS(VLC_META_COLLECTION)];
    [o_seqNum_lbl setStringValue: _NS(VLC_META_SEQ_NUM)];
    [o_description_lbl setStringValue: _NS(VLC_META_DESCRIPTION)];
    [o_rating_lbl setStringValue: _NS(VLC_META_RATING)];
    [o_date_lbl setStringValue: _NS(VLC_META_DATE)];
    [o_language_lbl setStringValue: _NS(VLC_META_LANGUAGE)];
    [o_nowPlaying_lbl setStringValue: _NS(VLC_META_NOW_PLAYING)];
    [o_publisher_lbl setStringValue: _NS(VLC_META_PUBLISHER)];
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
    
    /* statistics */
    [o_input_box setTitle: _NS("Input")];
    [o_read_bytes_lbl setStringValue: _NS("Read at media")];
    [o_input_bitrate_lbl setStringValue: _NS("Input bitrate")];
    [o_demux_bytes_lbl setStringValue: _NS("Demuxed")];
    [o_demux_bitrate_lbl setStringValue: _NS("Stream bitrate")];
    
    [o_video_box setTitle: _NS("Video")];
    [o_video_decoded_lbl setStringValue: _NS("Decoded blocks")];
    [o_displayed_lbl setStringValue: _NS("Displayed frames")];
    [o_lost_frames_lbl setStringValue: _NS("Lost frames")];
    
    [o_sout_box setTitle: _NS("Streaming")];
    [o_sent_packets_lbl setStringValue: _NS("Sent packets")];
    [o_sent_bytes_lbl setStringValue: _NS("Sent bytes")];
    [o_sent_bitrate_lbl setStringValue: _NS("Send rate")];
    
    [o_audio_box setTitle: _NS("Audio")];
    [o_audio_decoded_lbl setStringValue: _NS("Decoded blocks")];
    [o_played_abuffers_lbl setStringValue: _NS("Played buffers")];
    [o_lost_abuffers_lbl setStringValue: _NS("Lost buffers")];
Benjamin Pracht's avatar
Benjamin Pracht committed
99 100 101 102
}

- (IBAction)togglePlaylistInfoPanel:(id)sender
{
103 104 105 106 107 108
    if( [o_info_window isVisible] )
    {
        [o_info_window orderOut: sender];
    }
    else
    {
109
        p_item = [[[VLCMain sharedInstance] getPlaylist] selectedPlaylistItem];
110 111 112
        [self initPanel:sender];
    }
}
Benjamin Pracht's avatar
Benjamin Pracht committed
113

114 115
- (IBAction)toggleInfoPanel:(id)sender
{
Benjamin Pracht's avatar
Benjamin Pracht committed
116 117
    if( [o_info_window isVisible] )
    {
118
        [o_statUpdateTimer invalidate];
Benjamin Pracht's avatar
Benjamin Pracht committed
119 120 121 122
        [o_info_window orderOut: sender];
    }
    else
    {
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
123
        intf_thread_t * p_intf = VLCIntf;
124
        playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
Benjamin Pracht's avatar
Benjamin Pracht committed
125 126
                                          FIND_ANYWHERE );

127
        if( p_playlist )
Benjamin Pracht's avatar
Benjamin Pracht committed
128
        {
129
            p_item = p_playlist->status.p_item;
130
            vlc_object_release( p_playlist );
131
        }
132 133 134 135 136 137
        o_statUpdateTimer = [NSTimer scheduledTimerWithTimeInterval: 1 \
            target: self selector: @selector(updateStatistics:) \
            userInfo: nil repeats: YES]; 
        [o_statUpdateTimer fire];
        [o_statUpdateTimer retain];

138 139 140
        [self initPanel:sender];
    }
}
141

142 143
- (void)initPanel:(id)sender
{
144
    char *psz_temp;
145
    vlc_mutex_lock( &p_item->input.lock );
146

147
    /* fill uri / title / author info */
148
    if( p_item->input.psz_uri )
149 150
    {
        [o_uri_txt setStringValue:
151 152 153 154
            ([NSString stringWithUTF8String:p_item->input.psz_uri] == nil ) ?
            [NSString stringWithCString:p_item->input.psz_uri] :
            [NSString stringWithUTF8String:p_item->input.psz_uri]];
    }
155

156
    if( p_item->input.psz_name )
157
    {
158
        [o_title_txt setStringValue:
159 160 161 162
            ([NSString stringWithUTF8String:p_item->input.psz_name] == nil ) ?
            [NSString stringWithCString:p_item->input.psz_name] :
            [NSString stringWithUTF8String:p_item->input.psz_name]];
    }
163
    vlc_mutex_unlock( &p_item->input.lock );
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
164

165
    psz_temp = vlc_input_item_GetInfo( &p_item->input, _("Meta-information"), _("Artist") );
166

167
    if( psz_temp )
168 169
    {
        [o_author_txt setStringValue: [NSString stringWithUTF8String: psz_temp]];
170
        free( psz_temp );
Benjamin Pracht's avatar
Benjamin Pracht committed
171
    }
172

173 174 175 176 177 178 179 180 181 182 183 184 185
    /* fill the other fields */
    [self setMeta: VLC_META_GENRE forLabel: o_genre_txt];
    [self setMeta: VLC_META_COPYRIGHT forLabel: o_copyright_txt];
    [self setMeta: VLC_META_COLLECTION forLabel: o_collection_txt];
    [self setMeta: VLC_META_SEQ_NUM forLabel: o_seqNum_txt];
    [self setMeta: VLC_META_DESCRIPTION forLabel: o_description_txt];
    [self setMeta: VLC_META_RATING forLabel: o_rating_txt];
    [self setMeta: VLC_META_DATE forLabel: o_date_txt];
    [self setMeta: VLC_META_LANGUAGE forLabel: o_language_txt];
    [self setMeta: VLC_META_NOW_PLAYING forLabel: o_nowPlaying_txt];
    [self setMeta: VLC_META_PUBLISHER forLabel: o_publisher_txt];

    /* reload the advanced table */
186 187
    [[VLCInfoTreeItem rootItem] refresh];
    [o_outline_view reloadData];
188
    
189
    [self updateStatistics: nil];
190

191
    [o_info_window makeKeyAndOrderFront: sender];
Benjamin Pracht's avatar
Benjamin Pracht committed
192 193
}

194 195 196 197 198 199 200 201 202 203
- (void)setMeta: (char *)meta forLabel: (id)theItem
{
    char *psz_meta = vlc_input_item_GetInfo( &p_item->input, \
        _(VLC_META_INFO_CAT), _(meta) );
    if( psz_meta != NULL && *psz_meta)
        [theItem setStringValue: [NSString stringWithUTF8String: psz_meta]];
    else
        [theItem setStringValue: @"-"];
}

204
- (void)updateStatistics:(NSTimer*)theTimer
205
{
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
    if( [self isItemInPlaylist: p_item] )
    {
        /* we can only do that if there's a valid input around */
        
        vlc_mutex_lock( &p_item->input.p_stats->lock );

        /* input */
        [o_read_bytes_txt setStringValue: [NSString stringWithFormat: \
            @"%8.0f kB", (float)(p_item->input.p_stats->i_read_bytes)/1000]];
        [o_input_bitrate_txt setStringValue: [NSString stringWithFormat: \
            @"%6.0f kb/s", (float)(p_item->input.p_stats->f_input_bitrate)*8000]];
        [o_demux_bytes_txt setStringValue: [NSString stringWithFormat: \
            @"%8.0f kB", (float)(p_item->input.p_stats->i_demux_read_bytes)/1000]];
        [o_demux_bitrate_txt setStringValue: [NSString stringWithFormat: \
            @"%6.0f kb/s", (float)(p_item->input.p_stats->f_demux_bitrate)*8000]];

        /* Video */
        [o_video_decoded_txt setStringValue: [NSString stringWithFormat: @"%5i", \
            p_item->input.p_stats->i_decoded_video]];
        [o_displayed_txt setStringValue: [NSString stringWithFormat: @"%5i", \
            p_item->input.p_stats->i_displayed_pictures]];
        [o_lost_frames_txt setStringValue: [NSString stringWithFormat: @"%5i", \
            p_item->input.p_stats->i_lost_pictures]];

        /* Sout */
        [o_sent_packets_txt setStringValue: [NSString stringWithFormat: @"%5i", \
            p_item->input.p_stats->i_sent_packets]];
        [o_sent_bytes_txt setStringValue: [NSString stringWithFormat: @"%8.0f kB", \
            (float)(p_item->input.p_stats->i_sent_bytes)/1000]];
        [o_sent_bitrate_txt setStringValue: [NSString stringWithFormat: \
            @"%6.0f kb/s", (float)(p_item->input.p_stats->f_send_bitrate*8)*1000]];

        /* Audio */
        [o_audio_decoded_txt setStringValue: [NSString stringWithFormat: @"%5i", \
            p_item->input.p_stats->i_decoded_audio]];
        [o_played_abuffers_txt setStringValue: [NSString stringWithFormat: @"%5i", \
            p_item->input.p_stats->i_played_abuffers]];
        [o_lost_abuffers_txt setStringValue: [NSString stringWithFormat: @"%5i", \
            p_item->input.p_stats->i_lost_abuffers]];

        vlc_mutex_unlock( &p_item->input.p_stats->lock );
    }
248 249
}

Benjamin Pracht's avatar
Benjamin Pracht committed
250 251
- (IBAction)infoCancel:(id)sender
{
252
    [o_info_window orderOut: self];
Benjamin Pracht's avatar
Benjamin Pracht committed
253 254 255 256 257
}


- (IBAction)infoOk:(id)sender
{
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
258
    intf_thread_t * p_intf = VLCIntf;
Benjamin Pracht's avatar
Benjamin Pracht committed
259 260 261
    playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                          FIND_ANYWHERE );
    vlc_value_t val;
Benjamin Pracht's avatar
Benjamin Pracht committed
262

Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
263
    if( [self isItemInPlaylist: p_item] )
Benjamin Pracht's avatar
Benjamin Pracht committed
264
    {
265
        vlc_mutex_lock( &p_item->input.lock );
266

267 268 269
        p_item->input.psz_uri = strdup( [[o_uri_txt stringValue] UTF8String] );
        p_item->input.psz_name = strdup( [[o_title_txt stringValue] UTF8String] );
        vlc_mutex_unlock( &p_item->input.lock );
270
        vlc_input_item_AddInfo( &p_item->input, _("Meta-information"), _("Artist"), [[o_author_txt stringValue] UTF8String]);
271
        
Benjamin Pracht's avatar
Benjamin Pracht committed
272
        val.b_bool = VLC_TRUE;
273
        var_Set( p_playlist, "intf-change", val );
Benjamin Pracht's avatar
Benjamin Pracht committed
274
    }
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
275
    vlc_object_release( p_playlist );
276
    [o_info_window orderOut: self];
277 278
}

279
- (playlist_item_t *)getItem
280
{
281 282 283
    return p_item;
}

284
- (BOOL)isItemInPlaylist:(playlist_item_t *)p_local_item
285 286 287 288 289 290
{
    intf_thread_t * p_intf = VLCIntf;
    playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                          FIND_ANYWHERE );
    int i;

291
    if( p_playlist == NULL )
292 293 294 295
    {
        return NO;
    }

296
    for( i = 0 ; i < p_playlist->i_size ; i++ )
297
    {
298
        if( p_playlist->pp_items[i] == p_local_item )
299
        {
300
            vlc_object_release( p_playlist );
301 302 303
            return YES;
        }
    }
304
    vlc_object_release( p_playlist );
305
    return NO;
306
}
Benjamin Pracht's avatar
Benjamin Pracht committed
307

308 309
@end

310 311 312 313 314 315
@implementation VLCInfo (NSMenuValidation)

- (BOOL)validateMenuItem:(NSMenuItem *)o_mi
{
    BOOL bEnabled = TRUE;

Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
316
    intf_thread_t * p_intf = VLCIntf;
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332
    input_thread_t * p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT,
                                                       FIND_ANYWHERE );

    if( [[o_mi title] isEqualToString: _NS("Info")] )
    {
        if( p_input == NULL )
        {
            bEnabled = FALSE;
        }
    }
    if( p_input ) vlc_object_release( p_input );

    return( bEnabled );
}

@end
Benjamin Pracht's avatar
Benjamin Pracht committed
333

334
@implementation VLCInfo (NSTableDataSource)
335

336
- (int)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item
337 338 339 340 341 342 343 344
{
    return (item == nil) ? [[VLCInfoTreeItem rootItem] numberOfChildren] : [item numberOfChildren];
}

- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item {
    return ([item numberOfChildren] > 0);
}

345
- (id)outlineView:(NSOutlineView *)outlineView child:(int)index ofItem:(id)item
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361
{
    return (item == nil) ? [[VLCInfoTreeItem rootItem] childAtIndex:index] : [item childAtIndex:index];
}

- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
{
    if ([[tableColumn identifier] isEqualToString:@"0"])
    {
        return (item == nil) ? @"" : (id)[item getName];
    }
    else
    {
        return (item == nil) ? @"" : (id)[item getValue];
    }
}

362

363 364 365 366 367 368 369 370 371 372 373
@end

@implementation VLCInfoTreeItem

static VLCInfoTreeItem *o_root_item = nil;

#define IsALeafNode ((id)-1)

- (id)initWithName: (NSString *)o_item_name value: (NSString *)o_item_value ID: (int)i_id parent:(VLCInfoTreeItem *)o_parent_item
{
    self = [super init];
374

375 376 377 378 379 380
    if( self != nil )
    {
        o_name = [o_item_name copy];
        o_value = [o_item_value copy];
        i_object_id = i_id;
        o_parent = o_parent_item;
381 382 383 384
        if( [[VLCMain sharedInstance] getInfo] != nil )
            p_item = [[[VLCMain sharedInstance] getInfo] getItem];
        else
            p_item = NULL;
385 386 387 388 389 390 391 392 393 394 395
    }
    return( self );
}

+ (VLCInfoTreeItem *)rootItem {
    if (o_root_item == nil) o_root_item = [[VLCInfoTreeItem alloc] initWithName:@"main" value: @"" ID: 0 parent:nil];
    return o_root_item;
}

- (void)dealloc
{
396
    if( o_children != IsALeafNode ) [o_children release];
397 398 399 400 401 402 403 404 405 406 407 408
    [o_name release];
    [super dealloc];
}

/* Creates and returns the array of children
 * Loads children incrementally */
- (NSArray *)children
{
    if (o_children == NULL)
    {
        int i;

409
        if( [[[VLCMain sharedInstance] getInfo] isItemInPlaylist: p_item] )
410
        {
411
            if( self == o_root_item )
412
            {
413
                vlc_mutex_lock( &p_item->input.lock );
414 415
                o_children = [[NSMutableArray alloc] initWithCapacity:
                                                p_item->input.i_categories];
416
                for (i = 0 ; i < p_item->input.i_categories ; i++)
417
                {
418
                    [o_children addObject:[[VLCInfoTreeItem alloc]
419
                        initWithName: [NSString stringWithUTF8String:
420 421 422 423
                            p_item->input.pp_categories[i]->psz_name]
                        value: @""
                        ID: i
                        parent: self]];
424
                }
425
                vlc_mutex_unlock( &p_item->input.lock );
426
            }
427
            else if( o_parent == o_root_item )
428
            {
429
                vlc_mutex_lock( &p_item->input.lock );
430 431
                o_children = [[NSMutableArray alloc] initWithCapacity:
                    p_item->input.pp_categories[i_object_id]->i_infos];
432 433

                for (i = 0 ; i < p_item->input.pp_categories[i_object_id]->i_infos ; i++)
434
                {
435 436
                    [o_children addObject:[[VLCInfoTreeItem alloc]
                    initWithName: [NSString stringWithUTF8String:
437
                            p_item->input.pp_categories[i_object_id]->pp_infos[i]->psz_name]
438
                        value: [NSString stringWithUTF8String:
439
                            p_item->input.pp_categories[i_object_id]->pp_infos[i]->psz_value]
440 441
                        ID: i
                        parent: self]];
442
                }
443
                vlc_mutex_unlock( &p_item->input.lock );
444 445 446 447
            }
            else
            {
                o_children = IsALeafNode;
448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469
            }
        }
    }
    return o_children;
}

- (NSString *)getName
{
    return o_name;
}

- (NSString *)getValue
{
    return o_value;
}

- (VLCInfoTreeItem *)childAtIndex:(int)i_index {
    return [[self children] objectAtIndex:i_index];
}

- (int)numberOfChildren {
    id i_tmp = [self children];
470
    return ( i_tmp == IsALeafNode ) ? (-1) : (int)[i_tmp count];
471 472
}

473
/*- (int)selectedPlaylistItem
474
{
475
    return i_item;
476
}
477
*/
478 479
- (void)refresh
{
480
    p_item = [[[VLCMain sharedInstance] getInfo] getItem];
481
    if( o_children != NULL )
482 483 484 485 486
    {
        [o_children release];
        o_children = NULL;
    }
}
Benjamin Pracht's avatar
Benjamin Pracht committed
487 488 489

@end