]> git.sesse.net Git - vlc/blob - modules/gui/qt4/components/info_panels.cpp
Qt, stats: always show unsigned for blocks or buffers
[vlc] / modules / gui / qt4 / components / info_panels.cpp
1 /*****************************************************************************
2  * infopanels.cpp : Panels for the information dialogs
3  ****************************************************************************
4  * Copyright (C) 2006-2007 the VideoLAN team
5  * $Id$
6  *
7  * Authors: ClĂ©ment Stenac <zorglub@videolan.org>
8  *          Jean-Baptiste Kempf <jb@videolan.org>
9  *          Ilkka Ollakka <ileoo@videolan.org>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24  *****************************************************************************/
25
26 #define __STDC_FORMAT_MACROS 1
27 #define __STDC_CONSTANT_MACROS 1
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #include "qt4.hpp"
34 #include "components/info_panels.hpp"
35 #include "components/interface_widgets.hpp"
36
37 #include <assert.h>
38 #include <vlc_url.h>
39 #include <vlc_meta.h>
40
41 #include <QTreeWidget>
42 #include <QHeaderView>
43 #include <QList>
44 #include <QStringList>
45 #include <QGridLayout>
46 #include <QLineEdit>
47 #include <QLabel>
48 #include <QSpinBox>
49
50 /************************************************************************
51  * Single panels
52  ************************************************************************/
53
54 /**
55  * First Panel - Meta Info
56  * All the usual MetaData are displayed and can be changed.
57  **/
58 MetaPanel::MetaPanel( QWidget *parent,
59                       intf_thread_t *_p_intf )
60                       : QWidget( parent ), p_intf( _p_intf )
61 {
62     QGridLayout *metaLayout = new QGridLayout( this );
63     metaLayout->setVerticalSpacing( 12 );
64
65     int line = 0; /* Counter for GridLayout */
66     p_input = NULL;
67
68 #define ADD_META( string, widget ) {                                      \
69     metaLayout->addWidget( new QLabel( qtr( string ) + " :" ), line, 0 ); \
70     widget = new QLineEdit;                                               \
71     metaLayout->addWidget( widget, line, 1, 1, 9 );                       \
72     line++;            }
73
74     /* Title, artist and album*/
75     ADD_META( VLC_META_TITLE, title_text ); /* OK */
76     ADD_META( VLC_META_ARTIST, artist_text ); /* OK */
77     ADD_META( VLC_META_ALBUM, collection_text ); /* OK */
78
79     /* Genre Name */
80     /* TODO List id3genres.h is not includable yet ? */
81     genre_text = new QLineEdit;
82     metaLayout->addWidget( new QLabel( qtr( VLC_META_GENRE ) + " :" ), line, 0 );
83     metaLayout->addWidget( genre_text, line, 1, 1, 3 );
84
85     /* Number - on the same line */
86     metaLayout->addWidget( new QLabel( qtr( VLC_META_TRACK_NUMBER )  + " :" ),
87                   line, 5, 1, 2  );
88     seqnum_text = new QLineEdit;
89     seqnum_text->setInputMask("0000");
90     seqnum_text->setAlignment( Qt::AlignRight );
91     metaLayout->addWidget( seqnum_text, line, 7, 1, 3 );
92     line++;
93
94     /* Date (Should be in years) */
95     date_text = new QLineEdit;
96     date_text->setInputMask("0000");
97     date_text->setAlignment( Qt::AlignRight );
98     metaLayout->addWidget( new QLabel( qtr( VLC_META_DATE ) + " :" ), line, 0 );
99     metaLayout->addWidget( date_text, line, 1, 1, 3 );
100
101     /* Rating - on the same line */
102     /*
103     metaLayout->addWidget( new QLabel( qtr( VLC_META_RATING ) + " :" ), line, 4, 1, 2 );
104     rating_text = new QSpinBox; setSpinBounds( rating_text );
105     metaLayout->addWidget( rating_text, line, 6, 1, 1 );
106     */
107     /* Language on the same line */
108     metaLayout->addWidget( new QLabel( qfu( VLC_META_LANGUAGE ) + " :" ), line, 5, 1, 2 );
109     language_text = new QLineEdit;
110     language_text->setReadOnly( true );
111     metaLayout->addWidget( language_text, line,  7, 1, 3 );
112     line++;
113
114     /* ART_URL */
115     art_cover = new CoverArtLabel( this, p_intf );
116     metaLayout->addWidget( art_cover, line, 8, 4, 2, Qt::AlignRight );
117
118 /* Settings is unused */
119 /*    l->addWidget( new QLabel( qtr( VLC_META_SETTING ) + " :" ), line, 5 );
120     setting_text = new QLineEdit;
121     l->addWidget( setting_text, line, 6, 1, 4 ); */
122
123 /* Less used metadata */
124 #define ADD_META_2( string, widget ) {                                    \
125     metaLayout->addWidget( new QLabel( qtr( string ) + " :" ), line, 0 ); \
126     widget = new QLineEdit;                                               \
127     metaLayout->addWidget( widget, line, 1, 1, 7 );                       \
128     line++;            }
129
130     /* Now Playing - Useful for live feeds (HTTP, DVB, ETC...) */
131     ADD_META_2( VLC_META_NOW_PLAYING, nowplaying_text );
132     nowplaying_text->setReadOnly( true );
133     ADD_META_2( VLC_META_PUBLISHER, publisher_text );
134     ADD_META_2( VLC_META_COPYRIGHT, copyright_text );
135     ADD_META_2( N_("Comments"), description_text );
136
137 /* useless metadata */
138
139     //ADD_META_2( VLC_META_ENCODED_BY, encodedby_text );
140     /*  ADD_META( TRACKID )  Useless ? */
141     /*  ADD_URI - DO not show it, done outside */
142
143     metaLayout->setColumnStretch( 1, 2 );
144     metaLayout->setColumnMinimumWidth ( 1, 80 );
145     metaLayout->setRowStretch( line, 10 );
146 #undef ADD_META
147 #undef ADD_META_2
148
149     CONNECT( title_text, textEdited( QString ), this, enterEditMode() );
150     CONNECT( artist_text, textEdited( QString ), this, enterEditMode() );
151     CONNECT( collection_text, textEdited( QString ), this, enterEditMode() );
152     CONNECT( genre_text, textEdited( QString ), this, enterEditMode() );
153     CONNECT( seqnum_text, textEdited( QString ), this, enterEditMode() );
154
155     CONNECT( date_text, textEdited( QString ), this, enterEditMode() );
156     CONNECT( description_text, textEdited( QString ), this, enterEditMode() );
157 /*    CONNECT( rating_text, valueChanged( QString ), this, enterEditMode( QString ) );*/
158
159     /* We are not yet in Edit Mode */
160     b_inEditMode = false;
161 }
162
163 /**
164  * Update all the MetaData and art on an "item-changed" event
165  **/
166 void MetaPanel::update( input_item_t *p_item )
167 {
168     if( !p_item )
169     {
170         clear();
171         return;
172     }
173
174     /* Don't update if you are in edit mode */
175     if( b_inEditMode ) return;
176     else p_input = p_item;
177
178     char *psz_meta;
179 #define UPDATE_META( meta, widget ) {               \
180     psz_meta = input_item_Get##meta( p_item );      \
181     if( !EMPTY_STR( psz_meta ) )                    \
182         widget->setText( qfu( psz_meta ) );         \
183     else                                            \
184         widget->setText( "" ); }                    \
185     free( psz_meta );
186
187 #define UPDATE_META_INT( meta, widget ) {           \
188     psz_meta = input_item_Get##meta( p_item );      \
189     if( !EMPTY_STR( psz_meta ) )                    \
190         widget->setValue( atoi( psz_meta ) ); }     \
191     free( psz_meta );
192
193     /* Name / Title */
194     psz_meta = input_item_GetTitleFbName( p_item );
195     if( psz_meta )
196     {
197         title_text->setText( qfu( psz_meta ) );
198         free( psz_meta );
199     }
200     else
201         title_text->setText( "" );
202
203     /* URL / URI */
204     psz_meta = input_item_GetURL( p_item );
205     if( !EMPTY_STR( psz_meta ) )
206         emit uriSet( qfu( psz_meta ) );
207     else
208     {
209         free( psz_meta );
210         psz_meta = input_item_GetURI( p_item );
211         if( !EMPTY_STR( psz_meta ) )
212             emit uriSet( qfu( psz_meta ) );
213     }
214     free( psz_meta );
215
216     /* Other classic though */
217     UPDATE_META( Artist, artist_text );
218     UPDATE_META( Genre, genre_text );
219     UPDATE_META( Copyright, copyright_text );
220     UPDATE_META( Album, collection_text );
221     UPDATE_META( Description, description_text );
222     UPDATE_META( Language, language_text );
223     UPDATE_META( NowPlaying, nowplaying_text );
224     UPDATE_META( Publisher, publisher_text );
225 //    UPDATE_META( Setting, setting_text );
226 //FIXME this is wrong if has Publisher and EncodedBy fields
227     UPDATE_META( EncodedBy, publisher_text );
228
229     UPDATE_META( Date, date_text );
230     UPDATE_META( TrackNum, seqnum_text );
231 //    UPDATE_META_INT( Rating, rating_text );
232
233 #undef UPDATE_META_INT
234 #undef UPDATE_META
235
236     // If a artURL is available as a local file, directly display it !
237
238     QString file;
239     char *psz_art = input_item_GetArtURL( p_item );
240     if( psz_art )
241     {
242         char *psz = make_path( psz_art );
243         free( psz_art );
244         file = qfu( psz );
245         free( psz );
246     }
247
248     art_cover->showArtUpdate( file );
249
250 }
251
252 /**
253  * Save the MetaData, triggered by parent->save Button
254  **/
255 void MetaPanel::saveMeta()
256 {
257     if( p_input == NULL )
258         return;
259
260     /* now we read the modified meta data */
261     input_item_SetTitle(  p_input, qtu( title_text->text() ) );
262     input_item_SetArtist( p_input, qtu( artist_text->text() ) );
263     input_item_SetAlbum(  p_input, qtu( collection_text->text() ) );
264     input_item_SetGenre(  p_input, qtu( genre_text->text() ) );
265     input_item_SetTrackNum(  p_input, qtu( seqnum_text->text() ) );
266     input_item_SetDate(  p_input, qtu( date_text->text() ) );
267
268     input_item_SetCopyright( p_input, qtu( copyright_text->text() ) );
269     input_item_SetPublisher( p_input, qtu( publisher_text->text() ) );
270     input_item_SetDescription( p_input, qtu( description_text->text() ) );
271
272     playlist_t *p_playlist = pl_Get( p_intf );
273     input_item_WriteMeta( VLC_OBJECT(p_playlist), p_input );
274
275     /* Reset the status of the mode. No need to emit any signal because parent
276        is the only caller */
277     b_inEditMode = false;
278 }
279
280
281 bool MetaPanel::isInEditMode()
282 {
283     return b_inEditMode;
284 }
285
286 void MetaPanel::enterEditMode()
287 {
288     msg_Dbg( p_intf, "Entering Edit MetaData Mode" );
289     setEditMode( true );
290 }
291
292 void MetaPanel::setEditMode( bool b_editing )
293 {
294     b_inEditMode = b_editing;
295     if( b_editing )emit editing();
296 }
297
298 /*
299  * Clear all the metadata widgets
300  */
301 void MetaPanel::clear()
302 {
303     title_text->clear();
304     artist_text->clear();
305     genre_text->clear();
306     copyright_text->clear();
307     collection_text->clear();
308     seqnum_text->clear();
309     description_text->clear();
310     date_text->clear();
311     language_text->clear();
312     nowplaying_text->clear();
313     publisher_text->clear();
314
315     setEditMode( false );
316     emit uriSet( "" );
317 }
318
319 /**
320  * Second Panel - Shows the extra metadata in a tree, non editable.
321  **/
322 ExtraMetaPanel::ExtraMetaPanel( QWidget *parent,
323                                 intf_thread_t *_p_intf )
324                                 : QWidget( parent ), p_intf( _p_intf )
325 {
326      QGridLayout *layout = new QGridLayout(this);
327
328      QLabel *topLabel = new QLabel( qtr( "Extra metadata and other information"
329                  " are shown in this panel.\n" ) );
330      topLabel->setWordWrap( true );
331      layout->addWidget( topLabel, 0, 0 );
332
333      extraMetaTree = new QTreeWidget( this );
334      extraMetaTree->setAlternatingRowColors( true );
335      extraMetaTree->setColumnCount( 2 );
336      extraMetaTree->resizeColumnToContents( 0 );
337      extraMetaTree->header()->hide();
338      layout->addWidget( extraMetaTree, 1, 0 );
339 }
340
341 /**
342  * Update the Extra Metadata from p_meta->i_extras
343  **/
344 void ExtraMetaPanel::update( input_item_t *p_item )
345 {
346     if( !p_item )
347     {
348         clear();
349         return;
350     }
351
352     QList<QTreeWidgetItem *> items;
353
354     extraMetaTree->clear();
355
356     vlc_mutex_lock( &p_item->lock );
357     vlc_meta_t *p_meta = p_item->p_meta;
358     if( !p_meta )
359     {
360         vlc_mutex_unlock( &p_item->lock );
361         return;
362     }
363
364     char ** ppsz_allkey = vlc_meta_CopyExtraNames( p_meta);
365
366     for( int i = 0; ppsz_allkey[i] ; i++ )
367     {
368         const char * psz_value = vlc_meta_GetExtra( p_meta, ppsz_allkey[i] );
369         QStringList tempItem;
370         tempItem.append( qfu( ppsz_allkey[i] ) + " : ");
371         tempItem.append( qfu( psz_value ) );
372         items.append( new QTreeWidgetItem ( extraMetaTree, tempItem ) );
373         free( ppsz_allkey[i] );
374     }
375     vlc_mutex_unlock( &p_item->lock );
376     free( ppsz_allkey );
377
378     extraMetaTree->addTopLevelItems( items );
379     extraMetaTree->resizeColumnToContents( 0 );
380 }
381
382 /**
383  * Clear the ExtraMetaData Tree
384  **/
385 void ExtraMetaPanel::clear()
386 {
387     extraMetaTree->clear();
388 }
389
390 /**
391  * Third panel - Stream info
392  * Display all codecs and muxers info that we could gather.
393  **/
394 InfoPanel::InfoPanel( QWidget *parent,
395                       intf_thread_t *_p_intf )
396                       : QWidget( parent ), p_intf( _p_intf )
397 {
398      QGridLayout *layout = new QGridLayout(this);
399
400      QList<QTreeWidgetItem *> items;
401
402      QLabel *topLabel = new QLabel( qtr( "Information about what your media or"
403               " stream is made of.\nMuxer, Audio and Video Codecs, Subtitles "
404               "are shown." ) );
405      topLabel->setWordWrap( true );
406      layout->addWidget( topLabel, 0, 0 );
407
408      InfoTree = new QTreeWidget(this);
409      InfoTree->setColumnCount( 1 );
410      InfoTree->header()->hide();
411      InfoTree->header()->setResizeMode(QHeaderView::ResizeToContents);
412      layout->addWidget(InfoTree, 1, 0 );
413 }
414
415 /**
416  * Update the Codecs information on parent->update()
417  **/
418 void InfoPanel::update( input_item_t *p_item)
419 {
420     if( !p_item )
421     {
422         clear();
423         return;
424     }
425
426     InfoTree->clear();
427     QTreeWidgetItem *current_item = NULL;
428     QTreeWidgetItem *child_item = NULL;
429
430     for( int i = 0; i< p_item->i_categories ; i++)
431     {
432         current_item = new QTreeWidgetItem();
433         current_item->setText( 0, qfu(p_item->pp_categories[i]->psz_name) );
434         InfoTree->addTopLevelItem( current_item );
435
436         for( int j = 0 ; j < p_item->pp_categories[i]->i_infos ; j++ )
437         {
438             child_item = new QTreeWidgetItem ();
439             child_item->setText( 0,
440                     qfu(p_item->pp_categories[i]->pp_infos[j]->psz_name)
441                     + ": "
442                     + qfu(p_item->pp_categories[i]->pp_infos[j]->psz_value));
443
444             current_item->addChild(child_item);
445         }
446         InfoTree->setItemExpanded( current_item, true);
447     }
448 }
449
450 /**
451  * Clear the tree
452  **/
453 void InfoPanel::clear()
454 {
455     InfoTree->clear();
456 }
457
458 /**
459  * Save all the information to a file
460  * Not yet implemented.
461  **/
462 /*
463 void InfoPanel::saveCodecsInfo()
464 {}
465 */
466
467 /**
468  * Fourth Panel - Stats
469  * Displays the Statistics for reading/streaming/encoding/displaying in a tree
470  */
471 InputStatsPanel::InputStatsPanel( QWidget *parent,
472                                   intf_thread_t *_p_intf )
473                                   : QWidget( parent ), p_intf( _p_intf )
474 {
475      QGridLayout *layout = new QGridLayout(this);
476
477      QLabel *topLabel = new QLabel( qtr( "Current"
478                  " media / stream " "statistics") );
479      topLabel->setWordWrap( true );
480      layout->addWidget( topLabel, 0, 0 );
481
482      StatsTree = new QTreeWidget(this);
483      StatsTree->setColumnCount( 3 );
484      StatsTree->header()->hide();
485
486 #define CREATE_TREE_ITEM( itemName, itemText, itemValue, unit ) {              \
487     itemName =                                                                 \
488       new QTreeWidgetItem((QStringList () << itemText << itemValue << unit )); \
489     itemName->setTextAlignment( 1 , Qt::AlignRight ) ; }
490
491 #define CREATE_CATEGORY( catName, itemText ) {                           \
492     CREATE_TREE_ITEM( catName, itemText , "", "" );                      \
493     catName->setExpanded( true );                                        \
494     StatsTree->addTopLevelItem( catName );    }
495
496 #define CREATE_AND_ADD_TO_CAT( itemName, itemText, itemValue, catName, unit ){ \
497     CREATE_TREE_ITEM( itemName, itemText, itemValue, unit );                   \
498     catName->addChild( itemName ); }
499
500     /* Create the main categories */
501     CREATE_CATEGORY( audio, qtr("Audio") );
502     CREATE_CATEGORY( video, qtr("Video") );
503     CREATE_CATEGORY( input, qtr("Input/Read") );
504     CREATE_CATEGORY( streaming, qtr("Output/Written/Sent") );
505
506     CREATE_AND_ADD_TO_CAT( read_media_stat, qtr("Media data size"),
507                            "0", input , "KiB" );
508     CREATE_AND_ADD_TO_CAT( input_bitrate_stat, qtr("Input bitrate"),
509                            "0", input, "kb/s" );
510     CREATE_AND_ADD_TO_CAT( demuxed_stat, qtr("Demuxed data size"), "0", input, "KiB") ;
511     CREATE_AND_ADD_TO_CAT( stream_bitrate_stat, qtr("Content bitrate"),
512                            "0", input, "kb/s" );
513     CREATE_AND_ADD_TO_CAT( corrupted_stat, qtr("Discarded (corrupted)"),
514                            "0", input, "" );
515     CREATE_AND_ADD_TO_CAT( discontinuity_stat, qtr("Dropped (discontinued)"),
516                            "0", input, "" );
517
518     CREATE_AND_ADD_TO_CAT( vdecoded_stat, qtr("Decoded"),
519                            "0", video, qtr("blocks") );
520     CREATE_AND_ADD_TO_CAT( vdisplayed_stat, qtr("Displayed"),
521                            "0", video, qtr("frames") );
522     CREATE_AND_ADD_TO_CAT( vlost_frames_stat, qtr("Lost"),
523                            "0", video, qtr("frames") );
524
525     CREATE_AND_ADD_TO_CAT( send_stat, qtr("Sent"), "0", streaming, qtr("packets") );
526     CREATE_AND_ADD_TO_CAT( send_bytes_stat, qtr("Sent"),
527                            "0", streaming, "KiB" );
528     CREATE_AND_ADD_TO_CAT( send_bitrate_stat, qtr("Upstream rate"),
529                            "0", streaming, "kb/s" );
530
531     CREATE_AND_ADD_TO_CAT( adecoded_stat, qtr("Decoded"),
532                            "0", audio, qtr("blocks") );
533     CREATE_AND_ADD_TO_CAT( aplayed_stat, qtr("Played"),
534                            "0", audio, qtr("buffers") );
535     CREATE_AND_ADD_TO_CAT( alost_stat, qtr("Lost"), "0", audio, qtr("buffers") );
536
537 #undef CREATE_AND_ADD_TO_CAT
538 #undef CREATE_CATEGORY
539 #undef CREATE_TREE_ITEM
540
541     input->setExpanded( true );
542     video->setExpanded( true );
543     streaming->setExpanded( true );
544     audio->setExpanded( true );
545
546     StatsTree->resizeColumnToContents( 0 );
547     StatsTree->setColumnWidth( 1 , 200 );
548
549     layout->addWidget(StatsTree, 1, 0 );
550 }
551
552 /**
553  * Update the Statistics
554  **/
555 void InputStatsPanel::update( input_item_t *p_item )
556 {
557     assert( p_item );
558     vlc_mutex_lock( &p_item->p_stats->lock );
559
560 #define UPDATE( widget, format, calc... ) \
561     { QString str; widget->setText( 1 , str.sprintf( format, ## calc ) );  }
562
563     UPDATE( read_media_stat,     "%"PRIu64, (p_item->p_stats->i_read_bytes / 1024 ) );
564     UPDATE( input_bitrate_stat,  "%6.0f", (float)(p_item->p_stats->f_input_bitrate *  8000  ));
565     UPDATE( demuxed_stat,        "%"PRIu64, (p_item->p_stats->i_demux_read_bytes / 1024 ) );
566     UPDATE( stream_bitrate_stat, "%6.0f", (float)(p_item->p_stats->f_demux_bitrate *  8000  ));
567     UPDATE( corrupted_stat,      "%"PRIu64, p_item->p_stats->i_demux_corrupted );
568     UPDATE( discontinuity_stat,  "%"PRIu64, p_item->p_stats->i_demux_discontinuity );
569
570     /* Video */
571     UPDATE( vdecoded_stat,     "%"PRIu64, p_item->p_stats->i_decoded_video );
572     UPDATE( vdisplayed_stat,   "%"PRIu64, p_item->p_stats->i_displayed_pictures );
573     UPDATE( vlost_frames_stat, "%"PRIu64, p_item->p_stats->i_lost_pictures );
574
575     /* Sout */
576     UPDATE( send_stat,        "%"PRIu64, p_item->p_stats->i_sent_packets );
577     UPDATE( send_bytes_stat,  "%"PRIu64, (p_item->p_stats->i_sent_bytes)/ 1024 );
578     UPDATE( send_bitrate_stat, "%6.0f", (float)(p_item->p_stats->f_send_bitrate * 8000 ) );
579
580     /* Audio*/
581     UPDATE( adecoded_stat, "%"PRIu64, p_item->p_stats->i_decoded_audio );
582     UPDATE( aplayed_stat,  "%"PRIu64, p_item->p_stats->i_played_abuffers );
583     UPDATE( alost_stat,    "%"PRIu64, p_item->p_stats->i_lost_abuffers );
584
585 #undef UPDATE
586
587     vlc_mutex_unlock(& p_item->p_stats->lock );
588 }
589
590 void InputStatsPanel::clear()
591 {
592 }
593