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