]> git.sesse.net Git - vlc/blob - modules/gui/qt4/components/info_panels.cpp
506e6535992afd1efaceb4515559f3745b41db6d
[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 /*     QStringList headerList = ( QStringList() << qtr( "Type" )
339  *                                             << qtr( "Value" ) );
340  * Useless, add this header if you think it would help the user          **
341  */
342
343      layout->addWidget( extraMetaTree, 1, 0 );
344 }
345
346 /**
347  * Update the Extra Metadata from p_meta->i_extras
348  **/
349 void ExtraMetaPanel::update( input_item_t *p_item )
350 {
351     if( !p_item )
352     {
353         clear();
354         return;
355     }
356
357     QList<QTreeWidgetItem *> items;
358
359     extraMetaTree->clear();
360
361     vlc_mutex_lock( &p_item->lock );
362     vlc_meta_t *p_meta = p_item->p_meta;
363     if( !p_meta )
364     {
365         vlc_mutex_unlock( &p_item->lock );
366         return;
367     }
368
369     char ** ppsz_allkey = vlc_meta_CopyExtraNames( p_meta);
370
371     for( int i = 0; ppsz_allkey[i] ; i++ )
372     {
373         const char * psz_value = vlc_meta_GetExtra( p_meta, ppsz_allkey[i] );
374         QStringList tempItem;
375         tempItem.append( qfu( ppsz_allkey[i] ) + " : ");
376         tempItem.append( qfu( psz_value ) );
377         items.append( new QTreeWidgetItem ( extraMetaTree, tempItem ) );
378         free( ppsz_allkey[i] );
379     }
380     vlc_mutex_unlock( &p_item->lock );
381     free( ppsz_allkey );
382
383     extraMetaTree->addTopLevelItems( items );
384     extraMetaTree->resizeColumnToContents( 0 );
385 }
386
387 /**
388  * Clear the ExtraMetaData Tree
389  **/
390 void ExtraMetaPanel::clear()
391 {
392     extraMetaTree->clear();
393 }
394
395 /**
396  * Third panel - Stream info
397  * Display all codecs and muxers info that we could gather.
398  **/
399 InfoPanel::InfoPanel( QWidget *parent,
400                       intf_thread_t *_p_intf )
401                       : QWidget( parent ), p_intf( _p_intf )
402 {
403      QGridLayout *layout = new QGridLayout(this);
404
405      QList<QTreeWidgetItem *> items;
406
407      QLabel *topLabel = new QLabel( qtr( "Information about what your media or"
408               " stream is made of.\nMuxer, Audio and Video Codecs, Subtitles "
409               "are shown." ) );
410      topLabel->setWordWrap( true );
411      layout->addWidget( topLabel, 0, 0 );
412
413      InfoTree = new QTreeWidget(this);
414      InfoTree->setColumnCount( 1 );
415      InfoTree->setColumnWidth( 0, 20000 );
416      InfoTree->header()->hide();
417 //     InfoTree->header()->setStretchLastSection(false);
418 //     InfoTree->header()->setResizeMode(QHeaderView::ResizeToContents);
419      layout->addWidget(InfoTree, 1, 0 );
420 }
421
422 /**
423  * Update the Codecs information on parent->update()
424  **/
425 void InfoPanel::update( input_item_t *p_item)
426 {
427     if( !p_item )
428     {
429         clear();
430         return;
431     }
432
433     InfoTree->clear();
434     QTreeWidgetItem *current_item = NULL;
435     QTreeWidgetItem *child_item = NULL;
436
437     for( int i = 0; i< p_item->i_categories ; i++)
438     {
439         current_item = new QTreeWidgetItem();
440         current_item->setText( 0, qfu(p_item->pp_categories[i]->psz_name) );
441         InfoTree->addTopLevelItem( current_item );
442
443         for( int j = 0 ; j < p_item->pp_categories[i]->i_infos ; j++ )
444         {
445             child_item = new QTreeWidgetItem ();
446             child_item->setText( 0,
447                     qfu(p_item->pp_categories[i]->pp_infos[j]->psz_name)
448                     + ": "
449                     + qfu(p_item->pp_categories[i]->pp_infos[j]->psz_value));
450
451             current_item->addChild(child_item);
452         }
453          InfoTree->setItemExpanded( current_item, true);
454     }
455 }
456
457 /**
458  * Clear the tree
459  **/
460 void InfoPanel::clear()
461 {
462     InfoTree->clear();
463 }
464
465 /**
466  * Save all the information to a file
467  * Not yet implemented.
468  **/
469 /*
470 void InfoPanel::saveCodecsInfo()
471 {}
472 */
473
474 /**
475  * Fourth Panel - Stats
476  * Displays the Statistics for reading/streaming/encoding/displaying in a tree
477  */
478 InputStatsPanel::InputStatsPanel( QWidget *parent,
479                                   intf_thread_t *_p_intf )
480                                   : QWidget( parent ), p_intf( _p_intf )
481 {
482      QGridLayout *layout = new QGridLayout(this);
483
484      QList<QTreeWidgetItem *> items;
485
486      QLabel *topLabel = new QLabel( qtr( "Current"
487                  " media / stream " "statistics") );
488      topLabel->setWordWrap( true );
489      layout->addWidget( topLabel, 0, 0 );
490
491      StatsTree = new QTreeWidget(this);
492      StatsTree->setColumnCount( 3 );
493      StatsTree->header()->hide();
494
495 #define CREATE_TREE_ITEM( itemName, itemText, itemValue, unit ) {              \
496     itemName =                                                                 \
497       new QTreeWidgetItem((QStringList () << itemText << itemValue << unit )); \
498     itemName->setTextAlignment( 1 , Qt::AlignRight ) ; }
499
500 #define CREATE_CATEGORY( catName, itemText ) {                           \
501     CREATE_TREE_ITEM( catName, itemText , "", "" );                      \
502     catName->setExpanded( true );                                        \
503     StatsTree->addTopLevelItem( catName );    }
504
505 #define CREATE_AND_ADD_TO_CAT( itemName, itemText, itemValue, catName, unit ){ \
506     CREATE_TREE_ITEM( itemName, itemText, itemValue, unit );                   \
507     catName->addChild( itemName ); }
508
509     /* Create the main categories */
510     CREATE_CATEGORY( audio, qtr("Audio") );
511     CREATE_CATEGORY( video, qtr("Video") );
512     CREATE_CATEGORY( input, qtr("Input/Read") );
513     CREATE_CATEGORY( streaming, qtr("Output/Written/Sent") );
514
515     CREATE_AND_ADD_TO_CAT( read_media_stat, qtr("Media data size"),
516                            "0", input , "KiB" );
517     CREATE_AND_ADD_TO_CAT( input_bitrate_stat, qtr("Input bitrate"),
518                            "0", input, "kb/s" );
519     CREATE_AND_ADD_TO_CAT( demuxed_stat, qtr("Demuxed data size"), "0", input, "KiB") ;
520     CREATE_AND_ADD_TO_CAT( stream_bitrate_stat, qtr("Content bitrate"),
521                            "0", input, "kb/s" );
522     CREATE_AND_ADD_TO_CAT( corrupted_stat, qtr("Discarded (corrupted)"),
523                            "0", input, "" );
524     CREATE_AND_ADD_TO_CAT( discontinuity_stat, qtr("Dropped (discontinued)"),
525                            "0", input, "" );
526
527     CREATE_AND_ADD_TO_CAT( vdecoded_stat, qtr("Decoded"),
528                            "0", video, qtr("blocks") );
529     CREATE_AND_ADD_TO_CAT( vdisplayed_stat, qtr("Displayed"),
530                            "0", video, qtr("frames") );
531     CREATE_AND_ADD_TO_CAT( vlost_frames_stat, qtr("Lost"),
532                            "0", video, qtr("frames") );
533
534     CREATE_AND_ADD_TO_CAT( send_stat, qtr("Sent"), "0", streaming, qtr("packets") );
535     CREATE_AND_ADD_TO_CAT( send_bytes_stat, qtr("Sent"),
536                            "0", streaming, "KiB" );
537     CREATE_AND_ADD_TO_CAT( send_bitrate_stat, qtr("Upstream rate"),
538                            "0", streaming, "kb/s" );
539
540     CREATE_AND_ADD_TO_CAT( adecoded_stat, qtr("Decoded"),
541                            "0", audio, qtr("blocks") );
542     CREATE_AND_ADD_TO_CAT( aplayed_stat, qtr("Played"),
543                            "0", audio, qtr("buffers") );
544     CREATE_AND_ADD_TO_CAT( alost_stat, qtr("Lost"), "0", audio, qtr("buffers") );
545
546 #undef CREATE_AND_ADD_TO_CAT
547 #undef CREATE_CATEGORY
548 #undef CREATE_TREE_ITEM
549
550     input->setExpanded( true );
551     video->setExpanded( true );
552     streaming->setExpanded( true );
553     audio->setExpanded( true );
554
555     StatsTree->resizeColumnToContents( 0 );
556     StatsTree->setColumnWidth( 1 , 200 );
557
558     layout->addWidget(StatsTree, 1, 0 );
559 }
560
561 /**
562  * Update the Statistics
563  **/
564 void InputStatsPanel::update( input_item_t *p_item )
565 {
566     assert( p_item );
567     vlc_mutex_lock( &p_item->p_stats->lock );
568
569 #define UPDATE( widget, format, calc... ) \
570     { QString str; widget->setText( 1 , str.sprintf( format, ## calc ) );  }
571
572     UPDATE( read_media_stat, "%"PRId64,
573             (p_item->p_stats->i_read_bytes / 1024 ) );
574     UPDATE( input_bitrate_stat, "%6.0f",
575                     (float)(p_item->p_stats->f_input_bitrate *  8000  ));
576     UPDATE( demuxed_stat, "%"PRId64,
577                     (p_item->p_stats->i_demux_read_bytes / 1024 ) );
578     UPDATE( stream_bitrate_stat, "%6.0f",
579                     (float)(p_item->p_stats->f_demux_bitrate *  8000  ));
580     UPDATE( corrupted_stat, "%"PRId64, p_item->p_stats->i_demux_corrupted );
581     UPDATE( discontinuity_stat, "%"PRId64, p_item->p_stats->i_demux_discontinuity );
582
583     /* Video */
584     UPDATE( vdecoded_stat, "%"PRId64, p_item->p_stats->i_decoded_video );
585     UPDATE( vdisplayed_stat, "%"PRId64, p_item->p_stats->i_displayed_pictures );
586     UPDATE( vlost_frames_stat, "%"PRId64, p_item->p_stats->i_lost_pictures );
587
588     /* Sout */
589     UPDATE( send_stat, "%"PRId64, p_item->p_stats->i_sent_packets );
590     UPDATE( send_bytes_stat, "%"PRId64,
591             (p_item->p_stats->i_sent_bytes)/ 1024 );
592     UPDATE( send_bitrate_stat, "%6.0f",
593             (float)(p_item->p_stats->f_send_bitrate * 8000 ) );
594
595     /* Audio*/
596     UPDATE( adecoded_stat, "%"PRId64, p_item->p_stats->i_decoded_audio );
597     UPDATE( aplayed_stat, "%"PRId64, p_item->p_stats->i_played_abuffers );
598     UPDATE( alost_stat, "%"PRId64, p_item->p_stats->i_lost_abuffers );
599
600 #undef UPDATE
601
602     vlc_mutex_unlock(& p_item->p_stats->lock );
603 }
604
605 void InputStatsPanel::clear()
606 {
607 }
608