]> git.sesse.net Git - vlc/blob - modules/gui/qt4/dialogs/messages.cpp
Move vlc_atomic_t to <vlc_atomic.h> and correct definition
[vlc] / modules / gui / qt4 / dialogs / messages.cpp
1 /*****************************************************************************
2  * messages.cpp : Information about an item
3  ****************************************************************************
4  * Copyright (C) 2006-2011 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Jean-Baptiste Kempf <jb (at) videolan.org>
8  *
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.
13  *
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.
18  *
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  *****************************************************************************/
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
26
27 #include "dialogs/messages.hpp"
28
29 #include <QTextEdit>
30 #include <QTextCursor>
31 #include <QFileDialog>
32 #include <QTextStream>
33 #include <QMessageBox>
34 #include <QTabWidget>
35 #include <QTreeWidget>
36 #include <QTreeWidgetItem>
37 #include <QMutex>
38 #include <QLineEdit>
39 #include <QScrollBar>
40
41 #include <assert.h>
42
43 enum {
44     MsgEvent_Type = QEvent::User + MsgEventType + 1,
45 };
46
47 class MsgEvent : public QEvent
48 {
49 public:
50     MsgEvent( int, const msg_item_t *, const char * );
51
52     int priority;
53     uintptr_t object_id;
54     QString object_type;
55     QString header;
56     QString module;
57     QString text;
58 };
59
60 MsgEvent::MsgEvent( int type, const msg_item_t *msg, const char *text )
61     : QEvent( (QEvent::Type)MsgEvent_Type ),
62       priority( type ),
63       object_id( msg->i_object_id ),
64       object_type( qfu(msg->psz_object_type) ),
65       header( qfu(msg->psz_header) ),
66       module( qfu(msg->psz_module) ),
67       text( qfu(text) )
68 {
69 }
70
71 MessagesDialog::MessagesDialog( intf_thread_t *_p_intf)
72                : QVLCFrame( _p_intf )
73 {
74     setWindowTitle( qtr( "Messages" ) );
75     setWindowRole( "vlc-messages" );
76     /* Build Ui */
77     ui.setupUi( this );
78     ui.bottomButtonsBox->addButton( new QPushButton( qtr("&Close"), this ),
79                                          QDialogButtonBox::RejectRole );
80     updateTree();
81
82     /* Modules tree */
83     ui.modulesTree->setHeaderHidden( true );
84
85     /* Buttons and general layout */
86     ui.saveLogButton->setToolTip( qtr( "Saves all the displayed logs to a file" ) );
87
88     int i_verbosity = var_InheritInteger( p_intf, "verbose" );
89     changeVerbosity( i_verbosity );
90     ui.verbosityBox->setValue( i_verbosity );
91
92     char *objs = var_InheritString( p_intf, "verbose-objects" );
93     if( objs != NULL )
94     {
95         ui.vbobjectsEdit->setText( qfu(objs) );
96         free( objs );
97     }
98     updateConfig();
99     ui.vbobjectsEdit->setToolTip( "verbose-objects usage: \n"
100                             "--verbose-objects=+printthatobject,-dontprintthatone\n"
101                             "(keyword 'all' to applies to all objects)");
102
103     updateButton = new QPushButton( QIcon(":/update"), "" );
104     updateButton->setToolTip( qtr("Update the tree") );
105     ui.mainTab->setCornerWidget( updateButton );
106     updateButton->setVisible( false );
107     updateButton->setFlat( true );
108
109     BUTTONACT( ui.clearButton, clear() );
110     BUTTONACT( updateButton, updateTree() );
111     BUTTONACT( ui.saveLogButton, save() );
112     CONNECT( ui.vbobjectsEdit, editingFinished(), this, updateConfig());
113     CONNECT( ui.bottomButtonsBox, rejected(), this, hide() );
114     CONNECT( ui.verbosityBox, valueChanged( int ),
115              this, changeVerbosity( int ) );
116
117     CONNECT( ui.mainTab, currentChanged( int ), this, tabChanged( int ) );
118
119     /* General action */
120     readSettings( "Messages", QSize( 600, 450 ) );
121
122     /* Hook up to LibVLC messaging */
123     vlc_Subscribe( &sub, MsgCallback, this );
124 }
125
126 MessagesDialog::~MessagesDialog()
127 {
128     writeSettings( "Messages" );
129     vlc_Unsubscribe( &sub );
130 };
131
132 void MessagesDialog::changeVerbosity( int i_verbosity )
133 {
134     vlc_atomic_set( &this->verbosity, i_verbosity );
135 }
136
137 void MessagesDialog::updateConfig()
138 {
139     const QString& objects = ui.vbobjectsEdit->text();
140     /* FIXME: config item should be part of Qt4 module */
141     config_PutPsz(p_intf, "verbose-objects", qtu(objects));
142
143     QStringList filterOut, filterIn;
144     /* If a filter is set, disable by default */
145     /* If no filters are set, enable */
146     filterDefault = objects.isEmpty();
147     foreach( const QString& elem, objects.split(QChar(',')) )
148     {
149         QString object = elem;
150         bool add = true;
151
152         if( elem.startsWith(QChar('-')) )
153         {
154             add = false;
155             object.remove( 0, 1 );
156         }
157         else if( elem.startsWith(QChar('+')) )
158             object.remove( 0, 1 );
159
160         if( object.compare(qfu("all"), Qt::CaseInsensitive) == 0 )
161             filterDefault = add;
162         else
163             (add ? &filterIn : &filterOut)->append( object );
164     }
165     filter = filterDefault ? filterOut : filterIn;
166     filter.removeDuplicates();
167 }
168
169 void MessagesDialog::sinkMessage( const MsgEvent *msg )
170 {
171     if( (filter.contains(msg->module) || filter.contains(msg->object_type))
172                                                             == filterDefault )
173         return;
174
175     QTextEdit *messages = ui.messages;
176     /* Only scroll if the viewport is at the end.
177        Don't bug user by auto-changing/losing viewport on insert(). */
178     bool b_autoscroll = ( messages->verticalScrollBar()->value()
179                           + messages->verticalScrollBar()->pageStep()
180                           >= messages->verticalScrollBar()->maximum() );
181
182     /* Copy selected text to the clipboard */
183     if( messages->textCursor().hasSelection() )
184         messages->copy();
185
186     /* Fix selected text bug */
187     if( !messages->textCursor().atEnd() ||
188          messages->textCursor().anchor() != messages->textCursor().position() )
189          messages->moveCursor( QTextCursor::End );
190
191     messages->setFontItalic( true );
192     messages->setTextColor( "darkBlue" );
193     messages->insertPlainText( msg->module );
194
195     switch (msg->priority)
196     {
197         case VLC_MSG_INFO:
198             messages->setTextColor( "blue" );
199             messages->insertPlainText( " info: " );
200             break;
201         case VLC_MSG_ERR:
202             messages->setTextColor( "red" );
203             messages->insertPlainText( " error: " );
204             break;
205         case VLC_MSG_WARN:
206             messages->setTextColor( "green" );
207             messages->insertPlainText( " warning: " );
208             break;
209         case VLC_MSG_DBG:
210         default:
211             messages->setTextColor( "grey" );
212             messages->insertPlainText( " debug: " );
213             break;
214     }
215
216     /* Add message Regular black Font */
217     messages->setFontItalic( false );
218     messages->setTextColor( "black" );
219     messages->insertPlainText( msg->text );
220     messages->insertPlainText( "\n" );
221     if ( b_autoscroll ) messages->ensureCursorVisible();
222 }
223
224 void MessagesDialog::customEvent( QEvent *event )
225 {
226     MsgEvent *msge = static_cast<MsgEvent *>(event);
227
228     assert( msge );
229     sinkMessage( msge );
230 }
231
232 void MessagesDialog::clear()
233 {
234     ui.messages->clear();
235 }
236
237 bool MessagesDialog::save()
238 {
239     QString saveLogFileName = QFileDialog::getSaveFileName(
240             this, qtr( "Save log file as..." ),
241             QVLCUserDir( VLC_DOCUMENTS_DIR ),
242             qtr( "Texts / Logs (*.log *.txt);; All (*.*) ") );
243
244     if( !saveLogFileName.isNull() )
245     {
246         QFile file( saveLogFileName );
247         if ( !file.open( QFile::WriteOnly | QFile::Text ) ) {
248             QMessageBox::warning( this, qtr( "Application" ),
249                     qtr( "Cannot write to file %1:\n%2." )
250                     .arg( saveLogFileName )
251                     .arg( file.errorString() ) );
252             return false;
253         }
254
255         QTextStream out( &file );
256         out << ui.messages->toPlainText() << "\n";
257
258         return true;
259     }
260     return false;
261 }
262
263 void MessagesDialog::buildTree( QTreeWidgetItem *parentItem,
264                                 vlc_object_t *p_obj )
265 {
266     QTreeWidgetItem *item;
267
268     if( parentItem )
269         item = new QTreeWidgetItem( parentItem );
270     else
271         item = new QTreeWidgetItem( ui.modulesTree );
272
273     char *name = vlc_object_get_name( p_obj );
274     item->setText( 0, QString("%1%2 (0x%3)")
275                    .arg( qfu( p_obj->psz_object_type ) )
276                    .arg( ( name != NULL )
277                          ? QString( " \"%1\"" ).arg( qfu( name ) )
278                              : "" )
279                    .arg( (uintptr_t)p_obj, 0, 16 )
280                  );
281     free( name );
282     item->setExpanded( true );
283
284     vlc_list_t *l = vlc_list_children( p_obj );
285     for( int i=0; i < l->i_count; i++ )
286         buildTree( item, l->p_values[i].p_object );
287     vlc_list_release( l );
288 }
289
290 void MessagesDialog::updateTree()
291 {
292     ui.modulesTree->clear();
293     buildTree( NULL, VLC_OBJECT( p_intf->p_libvlc ) );
294 }
295
296 void MessagesDialog::tabChanged( int i )
297 {
298     updateButton->setVisible( i == 1 );
299 }
300
301 void MessagesDialog::MsgCallback( void *self, int type, const msg_item_t *item,
302                                   const char *format, va_list ap )
303 {
304     MessagesDialog *dialog = (MessagesDialog *)self;
305     char *str;
306     int verbosity = vlc_atomic_get( &dialog->verbosity );
307
308     if( verbosity < 0 || verbosity < (type - VLC_MSG_ERR)
309      || unlikely(vasprintf( &str, format, ap ) == -1) )
310         return;
311
312     int canc = vlc_savecancel();
313     QApplication::postEvent( dialog, new MsgEvent( type, item, str ) );
314     vlc_restorecancel( canc );
315     free( str );
316 }