]> git.sesse.net Git - vlc/blob - modules/gui/qt4/dialogs/extensions.cpp
e2da2712aaa19e8c0bb627ef61a5ea9589e1d98b
[vlc] / modules / gui / qt4 / dialogs / extensions.cpp
1 /*****************************************************************************
2  * extensions.cpp: Extensions manager for Qt: dialogs manager
3  ****************************************************************************
4  * Copyright (C) 2009-2010 VideoLAN and authors
5  * $Id$
6  *
7  * Authors: Jean-Philippe AndrĂ© < jpeg # 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
24 #include "extensions.hpp"
25 #include "../extensions_manager.hpp" // for isUnloading()
26
27 #include <vlc_dialog.h>
28
29 #include <QGridLayout>
30 #include <QPushButton>
31 #include <QSignalMapper>
32 #include <QLabel>
33 #include <QPixmap>
34 #include <QLineEdit>
35 #include <QTextBrowser>
36 #include <QCheckBox>
37 #include <QListWidget>
38 #include <QComboBox>
39 #include <QCloseEvent>
40
41 ExtensionsDialogProvider *ExtensionsDialogProvider::instance = NULL;
42
43 static int DialogCallback( vlc_object_t *p_this, const char *psz_variable,
44                            vlc_value_t old_val, vlc_value_t new_val,
45                            void *param );
46
47
48 ExtensionsDialogProvider::ExtensionsDialogProvider( intf_thread_t *_p_intf,
49                                                     extensions_manager_t *p_mgr )
50         : QObject( NULL ), p_intf( _p_intf ), p_extensions_manager( p_mgr )
51 {
52     // At this point, we consider that the Qt interface already called
53     // dialog_Register() in order to be the extension dialog provider
54     var_Create( p_intf, "dialog-extension", VLC_VAR_ADDRESS );
55     var_AddCallback( p_intf, "dialog-extension", DialogCallback, NULL );
56
57     CONNECT( this, SignalDialog( extension_dialog_t* ),
58              this, UpdateExtDialog( extension_dialog_t* ) );
59 }
60
61 ExtensionsDialogProvider::~ExtensionsDialogProvider()
62 {
63     var_DelCallback( p_intf, "dialog-extension", DialogCallback, NULL );
64 }
65
66 /** Create a dialog
67  * Note: Lock on p_dialog->lock must be held. */
68 ExtensionDialog* ExtensionsDialogProvider::CreateExtDialog(
69         extension_dialog_t *p_dialog )
70 {
71     ExtensionDialog *dialog = new ExtensionDialog( p_intf,
72                                                    p_extensions_manager,
73                                                    p_dialog );
74     p_dialog->p_sys_intf = (void*) dialog;
75     CONNECT( dialog, destroyDialog( extension_dialog_t* ),
76              this, DestroyExtDialog( extension_dialog_t* ) );
77     return dialog;
78 }
79
80 /** Destroy a dialog
81  * Note: Lock on p_dialog->lock must be held. */
82 int ExtensionsDialogProvider::DestroyExtDialog( extension_dialog_t *p_dialog )
83 {
84     assert( p_dialog );
85     ExtensionDialog *dialog = ( ExtensionDialog* ) p_dialog->p_sys_intf;
86     if( !dialog )
87         return VLC_EGENERIC;
88     delete dialog;
89     p_dialog->p_sys_intf = NULL;
90     return VLC_SUCCESS;
91 }
92
93 /**
94  * Update/Create/Destroy a dialog
95  **/
96 ExtensionDialog* ExtensionsDialogProvider::UpdateExtDialog(
97         extension_dialog_t *p_dialog )
98 {
99     assert( p_dialog );
100
101     ExtensionDialog *dialog = ( ExtensionDialog* ) p_dialog->p_sys_intf;
102     if( p_dialog->b_kill && !dialog )
103     {
104         /* This extension could not be activated properly but tried
105            to create a dialog. We must ignore it. */
106         return NULL;
107     }
108
109     vlc_mutex_lock( &p_dialog->lock );
110     if( !p_dialog->b_kill && !dialog )
111     {
112         dialog = CreateExtDialog( p_dialog );
113         dialog->setVisible( !p_dialog->b_hide );
114     }
115     else if( !p_dialog->b_kill && dialog )
116     {
117         dialog->has_lock = true;
118         dialog->UpdateWidgets();
119         dialog->has_lock = false;
120         dialog->setVisible( !p_dialog->b_hide );
121     }
122     else if( p_dialog->b_kill )
123     {
124         DestroyExtDialog( p_dialog );
125     }
126     vlc_cond_signal( &p_dialog->cond );
127     vlc_mutex_unlock( &p_dialog->lock );
128     return dialog;
129 }
130
131 /**
132  * Ask the dialog manager to create/update/kill the dialog. Thread-safe.
133  **/
134 void ExtensionsDialogProvider::ManageDialog( extension_dialog_t *p_dialog )
135 {
136     assert( p_dialog );
137     ExtensionsManager *extMgr = ExtensionsManager::getInstance( p_intf );
138     assert( extMgr != NULL );
139     if( !extMgr->isUnloading() )
140         emit SignalDialog( p_dialog ); // Safe because we signal Qt thread
141     else
142         UpdateExtDialog( p_dialog ); // This is safe, we're already in Qt thread
143 }
144
145 /**
146  * Ask the dialogs provider to create a new dialog
147  **/
148 static int DialogCallback( vlc_object_t *p_this, const char *psz_variable,
149                            vlc_value_t old_val, vlc_value_t new_val,
150                            void *param )
151 {
152     (void) p_this;
153     (void) psz_variable;
154     (void) old_val;
155     (void) param;
156
157     ExtensionsDialogProvider *p_edp = ExtensionsDialogProvider::getInstance();
158     if( !p_edp )
159         return VLC_EGENERIC;
160     if( !new_val.p_address )
161         return VLC_EGENERIC;
162
163     extension_dialog_t *p_dialog = ( extension_dialog_t* ) new_val.p_address;
164     p_edp->ManageDialog( p_dialog );
165     return VLC_SUCCESS;
166 }
167
168
169 ExtensionDialog::ExtensionDialog( intf_thread_t *_p_intf,
170                                   extensions_manager_t *p_mgr,
171                                   extension_dialog_t *_p_dialog )
172          : QDialog( NULL ), p_intf( _p_intf ), p_extensions_manager( p_mgr )
173          , p_dialog( _p_dialog ), has_lock(false)
174 {
175     assert( p_dialog );
176
177     msg_Dbg( p_intf, "Creating a new dialog: '%s'", p_dialog->psz_title );
178 #if HAS_QT45
179     this->setWindowFlags( Qt::WindowMinMaxButtonsHint
180                         | Qt::WindowCloseButtonHint );
181 #else
182     this->setWindowFlags( Qt::WindowMinMaxButtonsHint );
183 #endif
184
185     this->setWindowTitle( qfu( p_dialog->psz_title ) );
186
187     layout = new QGridLayout( this );
188     clickMapper = new QSignalMapper( this );
189     CONNECT( clickMapper, mapped( QObject* ), this, TriggerClick( QObject* ) );
190     inputMapper = new QSignalMapper( this );
191     CONNECT( inputMapper, mapped( QObject* ), this, SyncInput( QObject* ) );
192     selectMapper = new QSignalMapper( this );
193     CONNECT( selectMapper, mapped( QObject* ), this, SyncSelection(QObject*) );
194
195     UpdateWidgets();
196 }
197
198 ExtensionDialog::~ExtensionDialog()
199 {
200     msg_Dbg( p_intf, "Deleting extension dialog '%s'", qtu(windowTitle()) );
201     p_dialog->p_sys_intf = NULL;
202 }
203
204 QWidget* ExtensionDialog::CreateWidget( extension_widget_t *p_widget )
205 {
206     QLabel *label = NULL;
207     QPushButton *button = NULL;
208     QTextBrowser *textArea = NULL;
209     QLineEdit *textInput = NULL;
210     QCheckBox *checkBox = NULL;
211     QComboBox *comboBox = NULL;
212     QListWidget *list = NULL;
213     struct extension_widget_t::extension_widget_value_t *p_value = NULL;
214
215     assert( p_widget->p_sys_intf == NULL );
216
217     switch( p_widget->type )
218     {
219         case EXTENSION_WIDGET_LABEL:
220             label = new QLabel( qfu( p_widget->psz_text ), this );
221             p_widget->p_sys_intf = label;
222             label->setTextFormat( Qt::RichText );
223             //label->setFixedHeight( label->sizeHint().height );
224             return label;
225
226         case EXTENSION_WIDGET_BUTTON:
227             button = new QPushButton( qfu( p_widget->psz_text ), this );
228             clickMapper->setMapping( button, new WidgetMapper( p_widget ) );
229             CONNECT( button, clicked(), clickMapper, map() );
230             p_widget->p_sys_intf = button;
231             return button;
232
233         case EXTENSION_WIDGET_IMAGE:
234             label = new QLabel( this );
235             label->setPixmap( QPixmap( qfu( p_widget->psz_text ) ) );
236             if( p_widget->i_width > 0 )
237                 label->setMaximumWidth( p_widget->i_width );
238             if( p_widget->i_height > 0 )
239                 label->setMaximumHeight( p_widget->i_height );
240             label->setScaledContents( true );
241             p_widget->p_sys_intf = label;
242             return label;
243
244         case EXTENSION_WIDGET_HTML:
245             textArea = new QTextBrowser( this );
246             textArea->setOpenExternalLinks( true );
247             textArea->setHtml( qfu( p_widget->psz_text ) );
248             p_widget->p_sys_intf = textArea;
249             return textArea;
250
251         case EXTENSION_WIDGET_TEXT_FIELD:
252             textInput = new QLineEdit( this );
253             textInput->setText( qfu( p_widget->psz_text ) );
254             textInput->setReadOnly( false );
255             textInput->setEchoMode( QLineEdit::Normal );
256             inputMapper->setMapping( textInput, new WidgetMapper( p_widget ) );
257             /// @note: maybe it would be wiser to use textEdited here?
258             CONNECT( textInput, textChanged(const QString &),
259                      inputMapper, map() );
260             p_widget->p_sys_intf = textInput;
261             return textInput;
262
263         case EXTENSION_WIDGET_PASSWORD:
264             textInput = new QLineEdit( this );
265             textInput->setText( qfu( p_widget->psz_text ) );
266             textInput->setReadOnly( false );
267             textInput->setEchoMode( QLineEdit::Password );
268             inputMapper->setMapping( textInput, new WidgetMapper( p_widget ) );
269             /// @note: maybe it would be wiser to use textEdited here?
270             CONNECT( textInput, textChanged(const QString &),
271                      inputMapper, map() );
272             p_widget->p_sys_intf = textInput;
273             return textInput;
274
275         case EXTENSION_WIDGET_CHECK_BOX:
276             checkBox = new QCheckBox( this );
277             checkBox->setText( qfu( p_widget->psz_text ) );
278             checkBox->setChecked( p_widget->b_checked );
279             clickMapper->setMapping( checkBox, new WidgetMapper( p_widget ) );
280             CONNECT( checkBox, stateChanged( int ), clickMapper, map() );
281             p_widget->p_sys_intf = checkBox;
282             return checkBox;
283
284         case EXTENSION_WIDGET_DROPDOWN:
285             comboBox = new QComboBox( this );
286             comboBox->setEditable( false );
287             for( p_value = p_widget->p_values;
288                  p_value != NULL;
289                  p_value = p_value->p_next )
290             {
291                 comboBox->addItem( qfu( p_value->psz_text ), p_value->i_id );
292             }
293             /* Set current item */
294             if( p_widget->psz_text )
295             {
296                 int idx = comboBox->findText( qfu( p_widget->psz_text ) );
297                 if( idx >= 0 )
298                     comboBox->setCurrentIndex( idx );
299             }
300             selectMapper->setMapping( comboBox, new WidgetMapper( p_widget ) );
301             CONNECT( comboBox, currentIndexChanged( const QString& ),
302                      selectMapper, map() );
303             return comboBox;
304
305         case EXTENSION_WIDGET_LIST:
306             list = new QListWidget( this );
307             list->setSelectionMode( QAbstractItemView::ExtendedSelection );
308             for( p_value = p_widget->p_values;
309                  p_value != NULL;
310                  p_value = p_value->p_next )
311             {
312                 QListWidgetItem *item =
313                     new QListWidgetItem( qfu( p_value->psz_text ) );
314                 item->setData( Qt::UserRole, p_value->i_id );
315                 list->addItem( item );
316             }
317             selectMapper->setMapping( list, new WidgetMapper( p_widget ) );
318             CONNECT( list, itemSelectionChanged(),
319                      selectMapper, map() );
320             return list;
321
322         default:
323             msg_Err( p_intf, "Widget type %d unknown", p_widget->type );
324             return NULL;
325     }
326 }
327
328 /**
329  * Forward click event to the extension
330  * @param object A WidgetMapper, whose data() is the p_widget
331  **/
332 int ExtensionDialog::TriggerClick( QObject *object )
333 {
334     assert( object != NULL );
335     WidgetMapper *mapping = static_cast< WidgetMapper* >( object );
336     extension_widget_t *p_widget = mapping->getWidget();
337
338     QCheckBox *checkBox = NULL;
339     int i_ret = VLC_EGENERIC;
340
341     bool lockedHere = false;
342     if( !has_lock )
343     {
344         vlc_mutex_lock( &p_dialog->lock );
345         has_lock = true;
346         lockedHere = true;
347     }
348
349     switch( p_widget->type )
350     {
351         case EXTENSION_WIDGET_BUTTON:
352             i_ret = extension_WidgetClicked( p_dialog, p_widget );
353             break;
354
355         case EXTENSION_WIDGET_CHECK_BOX:
356             checkBox = static_cast< QCheckBox* >( p_widget->p_sys_intf );
357             p_widget->b_checked = checkBox->isChecked();
358             i_ret = VLC_SUCCESS;
359             break;
360
361         default:
362             msg_Dbg( p_intf, "A click event was triggered by a wrong widget" );
363             break;
364     }
365
366     if( lockedHere )
367     {
368         vlc_mutex_unlock( &p_dialog->lock );
369         has_lock = false;
370     }
371
372     return i_ret;
373 }
374
375 /**
376  * Synchronize psz_text with the widget's text() value on update
377  * @param object A WidgetMapper
378  **/
379 void ExtensionDialog::SyncInput( QObject *object )
380 {
381     assert( object != NULL );
382
383     bool lockedHere = false;
384     if( !has_lock )
385     {
386         vlc_mutex_lock( &p_dialog->lock );
387         has_lock = true;
388         lockedHere = true;
389     }
390
391     WidgetMapper *mapping = static_cast< WidgetMapper* >( object );
392     extension_widget_t *p_widget = mapping->getWidget();
393     assert( p_widget->type == EXTENSION_WIDGET_TEXT_FIELD
394             || p_widget->type == EXTENSION_WIDGET_PASSWORD );
395     /* Synchronize psz_text with the new value */
396     QLineEdit *widget = static_cast< QLineEdit* >( p_widget->p_sys_intf );
397     char *psz_text = widget->text().isNull() ? NULL : strdup( qtu( widget->text() ) );
398     free( p_widget->psz_text );
399     p_widget->psz_text =  psz_text;
400
401     if( lockedHere )
402     {
403         vlc_mutex_unlock( &p_dialog->lock );
404         has_lock = false;
405     }
406 }
407
408 /**
409  * Synchronize parameter b_selected in the values list
410  * @param object A WidgetMapper
411  **/
412 void ExtensionDialog::SyncSelection( QObject *object )
413 {
414     assert( object != NULL );
415     struct extension_widget_t::extension_widget_value_t *p_value;
416
417     bool lockedHere = false;
418     if( !has_lock )
419     {
420         vlc_mutex_lock( &p_dialog->lock );
421         has_lock = true;
422         lockedHere = true;
423     }
424
425     WidgetMapper *mapping = static_cast< WidgetMapper* >( object );
426     extension_widget_t *p_widget = mapping->getWidget();
427     assert( p_widget->type == EXTENSION_WIDGET_DROPDOWN
428             || p_widget->type == EXTENSION_WIDGET_LIST );
429
430     if( p_widget->type == EXTENSION_WIDGET_DROPDOWN )
431     {
432         QComboBox *combo = static_cast< QComboBox* >( p_widget->p_sys_intf );
433         for( p_value = p_widget->p_values;
434              p_value != NULL;
435              p_value = p_value->p_next )
436         {
437 //             if( !qstrcmp( p_value->psz_text, qtu( combo->currentText() ) ) )
438             if( combo->itemData( combo->currentIndex(), Qt::UserRole ).toInt()
439                 == p_value->i_id )
440             {
441                 p_value->b_selected = true;
442             }
443             else
444             {
445                 p_value->b_selected = false;
446             }
447         }
448         free( p_widget->psz_text );
449         p_widget->psz_text = strdup( qtu( combo->currentText() ) );
450     }
451     else if( p_widget->type == EXTENSION_WIDGET_LIST )
452     {
453         QListWidget *list = static_cast<QListWidget*>( p_widget->p_sys_intf );
454         QList<QListWidgetItem *> selection = list->selectedItems();
455         for( p_value = p_widget->p_values;
456              p_value != NULL;
457              p_value = p_value->p_next )
458         {
459             bool b_selected = false;
460             foreach( const QListWidgetItem *item, selection )
461             {
462 //                 if( !qstrcmp( qtu( item->text() ), p_value->psz_text ) )
463                 if( item->data( Qt::UserRole ).toInt() == p_value->i_id )
464                 {
465                     b_selected = true;
466                     break;
467                 }
468             }
469             p_value->b_selected = b_selected;
470         }
471     }
472
473     if( lockedHere )
474     {
475         vlc_mutex_unlock( &p_dialog->lock );
476         has_lock = false;
477     }
478 }
479
480 void ExtensionDialog::UpdateWidgets()
481 {
482     assert( p_dialog );
483     extension_widget_t *p_widget;
484     FOREACH_ARRAY( p_widget, p_dialog->widgets )
485     {
486         if( !p_widget ) continue; /* Some widgets may be NULL at this point */
487         QWidget *widget;
488         int row = p_widget->i_row - 1;
489         int col = p_widget->i_column - 1;
490         if( row < 0 )
491         {
492             row = layout->rowCount();
493             col = 0;
494         }
495         else if( col < 0 )
496             col = layout->columnCount();
497         int hsp = __MAX( 1, p_widget->i_horiz_span );
498         int vsp = __MAX( 1, p_widget->i_vert_span );
499         if( !p_widget->p_sys_intf && !p_widget->b_kill )
500         {
501             widget = CreateWidget( p_widget );
502             if( !widget )
503             {
504                 msg_Warn( p_intf, "Could not create a widget for dialog %s",
505                           p_dialog->psz_title );
506                 continue;
507             }
508             widget->setVisible( !p_widget->b_hide );
509             layout->addWidget( widget, row, col, vsp, hsp );
510             if( ( p_widget->i_width > 0 ) && ( p_widget->i_height > 0 ) )
511                 widget->resize( p_widget->i_width, p_widget->i_height );
512             p_widget->p_sys_intf = widget;
513             this->resize( sizeHint() );
514         }
515         else if( p_widget->p_sys_intf && !p_widget->b_kill
516                  && p_widget->b_update )
517         {
518             widget = UpdateWidget( p_widget );
519             if( !widget )
520             {
521                 msg_Warn( p_intf, "Could not update a widget for dialog %s",
522                           p_dialog->psz_title );
523                 return;
524             }
525             widget->setVisible( !p_widget->b_hide );
526             layout->addWidget( widget, row, col, vsp, hsp );
527             if( ( p_widget->i_width > 0 ) && ( p_widget->i_height > 0 ) )
528                 widget->resize( p_widget->i_width, p_widget->i_height );
529             p_widget->p_sys_intf = widget;
530             this->resize( sizeHint() );
531
532             /* Do not update again */
533             p_widget->b_update = false;
534         }
535         else if( p_widget->p_sys_intf && p_widget->b_kill )
536         {
537             DestroyWidget( p_widget );
538             p_widget->p_sys_intf = NULL;
539             this->resize( sizeHint() );
540         }
541     }
542     FOREACH_END()
543 }
544
545 QWidget* ExtensionDialog::UpdateWidget( extension_widget_t *p_widget )
546 {
547     QLabel *label = NULL;
548     QPushButton *button = NULL;
549     QTextBrowser *textArea = NULL;
550     QLineEdit *textInput = NULL;
551     QCheckBox *checkBox = NULL;
552     QComboBox *comboBox = NULL;
553     QListWidget *list = NULL;
554     struct extension_widget_t::extension_widget_value_t *p_value = NULL;
555
556     assert( p_widget->p_sys_intf != NULL );
557
558     switch( p_widget->type )
559     {
560         case EXTENSION_WIDGET_LABEL:
561             label = static_cast< QLabel* >( p_widget->p_sys_intf );
562             label->setText( qfu( p_widget->psz_text ) );
563             return label;
564
565         case EXTENSION_WIDGET_BUTTON:
566             // FIXME: looks like removeMappings does not work
567             button = static_cast< QPushButton* >( p_widget->p_sys_intf );
568             button->setText( qfu( p_widget->psz_text ) );
569             clickMapper->removeMappings( button );
570             clickMapper->setMapping( button, new WidgetMapper( p_widget ) );
571             CONNECT( button, clicked(), clickMapper, map() );
572             return button;
573
574         case EXTENSION_WIDGET_IMAGE:
575             label = static_cast< QLabel* >( p_widget->p_sys_intf );
576             label->setPixmap( QPixmap( qfu( p_widget->psz_text ) ) );
577             return label;
578
579         case EXTENSION_WIDGET_HTML:
580             textArea = static_cast< QTextBrowser* >( p_widget->p_sys_intf );
581             textArea->setHtml( qfu( p_widget->psz_text ) );
582             return textArea;
583
584         case EXTENSION_WIDGET_TEXT_FIELD:
585             textInput = static_cast< QLineEdit* >( p_widget->p_sys_intf );
586             textInput->setText( qfu( p_widget->psz_text ) );
587             return textInput;
588
589         case EXTENSION_WIDGET_PASSWORD:
590             textInput = static_cast< QLineEdit* >( p_widget->p_sys_intf );
591             textInput->setText( qfu( p_widget->psz_text ) );
592             return textInput;
593
594         case EXTENSION_WIDGET_CHECK_BOX:
595             checkBox = static_cast< QCheckBox* >( p_widget->p_sys_intf );
596             checkBox->setText( qfu( p_widget->psz_text ) );
597             checkBox->setChecked( p_widget->b_checked );
598             return checkBox;
599
600         case EXTENSION_WIDGET_DROPDOWN:
601             comboBox = static_cast< QComboBox* >( p_widget->p_sys_intf );
602             comboBox->clear();
603             for( p_value = p_widget->p_values;
604                  p_value != NULL;
605                  p_value = p_value->p_next )
606             {
607                 comboBox->addItem( qfu( p_value->psz_text ), p_value->i_id );
608             }
609             /* Set current item */
610             if( p_widget->psz_text )
611             {
612                 int idx = comboBox->findText( qfu( p_widget->psz_text ) );
613                 if( idx >= 0 )
614                     comboBox->setCurrentIndex( idx );
615             }
616             return comboBox;
617
618         case EXTENSION_WIDGET_LIST:
619             list = static_cast< QListWidget* >( p_widget->p_sys_intf );
620             list->clear();
621             for( p_value = p_widget->p_values;
622                  p_value != NULL;
623                  p_value = p_value->p_next )
624             {
625                 QListWidgetItem *item =
626                         new QListWidgetItem( qfu( p_value->psz_text ) );
627                 item->setData( Qt::UserRole, p_value->i_id );
628                 list->addItem( item );
629             }
630             return list;
631
632         default:
633             msg_Err( p_intf, "Widget type %d unknown", p_widget->type );
634             return NULL;
635     }
636 }
637
638 void ExtensionDialog::DestroyWidget( extension_widget_t *p_widget )
639 {
640     assert( p_widget && p_widget->b_kill );
641     QWidget *widget = static_cast< QWidget* >( p_widget->p_sys_intf );
642     delete widget;
643     p_widget->p_sys_intf = NULL;
644 }
645
646 /** Implement closeEvent() in order to intercept the event */
647 void ExtensionDialog::closeEvent( QCloseEvent *event )
648 {
649     assert( p_dialog != NULL );
650     extension_DialogClosed( p_dialog );
651     event->accept();
652     emit destroyDialog( p_dialog );
653 }
654