knotifydialog.cpp

00001 /*
00002   Copyright (C) 2000,2002 Carsten Pfeiffer <pfeiffer@kde.org>
00003   Copyright (C) 2002 Neil Stevens <neil@qualityassistant.com>
00004 
00005   This program is free software; you can redistribute it and/or
00006   modify it under the terms of the GNU Library General Public
00007   License version 2 as published by the Free Software Foundation;
00008 
00009   This program is distributed in the hope that it will be useful,
00010   but WITHOUT ANY WARRANTY; without even the implied warranty of
00011   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012   General Public License for more details.
00013 
00014   You should have received a copy of the GNU Library General Public License
00015   along with this library,  If not, write to the Free Software Foundation,
00016   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017 */
00018 
00019 #include <dcopclient.h>
00020 
00021 #include <kaboutdata.h>
00022 #include <kapplication.h>
00023 #include <kaudioplayer.h>
00024 #include <kcombobox.h>
00025 #include <kconfig.h>
00026 #include <kcursor.h>
00027 #include <kdebug.h>
00028 #include <kfiledialog.h>
00029 #include <kiconloader.h>
00030 #include <kicontheme.h>
00031 #include <klineedit.h>
00032 #include <klocale.h>
00033 #include <kmessagebox.h>
00034 #include <knotifyclient.h>
00035 #include <knotifydialog.h>
00036 #include <kstandarddirs.h>
00037 #include <kurlrequester.h>
00038 #include <kio/netaccess.h>
00039 
00040 #include <qcheckbox.h>
00041 #include <qgroupbox.h>
00042 #include <qheader.h>
00043 #include <qlabel.h>
00044 #include <qlistview.h>
00045 #include <qlayout.h>
00046 #include <qptrlist.h>
00047 #include <qpushbutton.h>
00048 #include <qstring.h>
00049 #include <qtooltip.h>
00050 #include <qtimer.h>
00051 #include <qvbox.h>
00052 #include <qwhatsthis.h>
00053 
00054 using namespace KNotify;
00055 
00056 enum
00057 {
00058     COL_EXECUTE = 0,
00059     COL_STDERR  = 1,
00060     COL_MESSAGE = 2,
00061     COL_LOGFILE = 3,
00062     COL_SOUND   = 4,
00063     COL_TASKBAR = 5,
00064     COL_EVENT   = 6
00065 };
00066 
00067 //
00068 // I don't feel like subclassing KComboBox and find ways to insert that into
00069 // the .ui file...
00070 //
00071 namespace KNotify
00072 {
00073     class SelectionCombo
00074     {
00075     public:
00076         //
00077         // Mind the order in fill() and type()
00078         //
00079         static void fill( KComboBox *combo )
00080         {
00081             combo->insertItem( i18n("Sounds") );
00082             combo->insertItem( i18n("Logging") );
00083             combo->insertItem( i18n("Program Execution") );
00084             combo->insertItem( i18n("Message Windows") );
00085             combo->insertItem( i18n("Passive Windows") );
00086             combo->insertItem( i18n("Standard Error Output") );
00087             combo->insertItem( i18n("Taskbar") );
00088         }
00089 
00090         static int type( KComboBox *combo )
00091         {
00092             switch( combo->currentItem() )
00093             {
00094                 case 0:
00095                     return KNotifyClient::Sound;
00096                 case 1:
00097                     return KNotifyClient::Logfile;
00098                 case 2:
00099                     return KNotifyClient::Execute;
00100                 case 3:
00101                     return KNotifyClient::Messagebox;
00102                 case 4:
00103                     return KNotifyClient::PassivePopup;
00104                 case 5:
00105                     return KNotifyClient::Stderr;
00106                 case 6:
00107                     return KNotifyClient::Taskbar;
00108             }
00109 
00110             return KNotifyClient::None;
00111         }
00112     };
00113 
00114     // Needed for displaying tooltips in the listview's QHeader
00115     class KNotifyToolTip : public QToolTip
00116     {
00117     public:
00118         KNotifyToolTip( QHeader *header )
00119             : QToolTip( header )
00120         {
00121             m_tips[COL_EXECUTE] = i18n("Execute a program");
00122             m_tips[COL_STDERR]  = i18n("Print to Standard error output");
00123             m_tips[COL_MESSAGE] = i18n("Display a messagebox");
00124             m_tips[COL_LOGFILE] = i18n("Log to a file");
00125             m_tips[COL_SOUND]   = i18n("Play a sound");
00126             m_tips[COL_TASKBAR] = i18n("Flash the taskbar entry");
00127         }
00128         virtual ~KNotifyToolTip() {}
00129 
00130     protected:
00131         virtual void maybeTip ( const QPoint& p )
00132         {
00133             QHeader *header = static_cast<QHeader*>( parentWidget() );
00134             int section = 0;
00135 
00136             if ( header->orientation() == Horizontal )
00137                 section= header->sectionAt( p.x() );
00138             else
00139                 section= header->sectionAt( p.y() );
00140 
00141             if ( ( section < 0 ) || ( static_cast<uint>( section ) >= (sizeof(m_tips) / sizeof(QString)) ) )
00142                 return;
00143 
00144             tip( header->sectionRect( section ), m_tips[section] );
00145         }
00146 
00147     private:
00148         QString m_tips[6];
00149     };
00150 
00151 }
00152 
00153 
00154 int KNotifyDialog::configure( QWidget *parent, const char *name,
00155                               const KAboutData *aboutData )
00156 {
00157     KNotifyDialog dialog( parent, name, true, aboutData );
00158     return dialog.exec();
00159 }
00160 
00161 KNotifyDialog::KNotifyDialog( QWidget *parent, const char *name, bool modal,
00162                               const KAboutData *aboutData )
00163     : KDialogBase(parent, name, modal, i18n("Notification Settings"),
00164                   Ok | Apply | Cancel | Default, Ok, true )
00165 {
00166     QVBox *box = makeVBoxMainWidget();
00167 
00168     m_notifyWidget = new KNotifyWidget( box, "knotify widget" );
00169 
00170     if ( aboutData )
00171         addApplicationEvents( aboutData->appName() );
00172 
00173     connect( this, SIGNAL( okClicked() ), m_notifyWidget, SLOT( save() ));
00174     connect( this, SIGNAL( applyClicked() ), m_notifyWidget, SLOT( save() ));
00175 }
00176 
00177 KNotifyDialog::~KNotifyDialog()
00178 {
00179 }
00180 
00181 void KNotifyDialog::addApplicationEvents( const char *appName )
00182 {
00183     addApplicationEvents( QString::fromUtf8( appName ) +
00184                           QString::fromLatin1( "/eventsrc" ) );
00185 }
00186 
00187 void KNotifyDialog::addApplicationEvents( const QString& path )
00188 {
00189     Application *app = m_notifyWidget->addApplicationEvents( path );
00190     if ( app )
00191     {
00192         m_notifyWidget->addVisibleApp( app );
00193         m_notifyWidget->sort();
00194     }
00195 }
00196 
00197 void KNotifyDialog::clearApplicationEvents()
00198 {
00199     m_notifyWidget->clear();
00200 }
00201 
00202 void KNotifyDialog::slotDefault()
00203 {
00204     m_notifyWidget->resetDefaults( true ); // ask user
00205 }
00206 
00207 
00210 
00211 
00212 class KNotifyWidget::Private
00213 {
00214 public:
00215     QPixmap pixmaps[6];
00216     KNotifyToolTip *toolTip;
00217 };
00218 
00219 // simple access to all knotify-handled applications
00220 KNotifyWidget::KNotifyWidget( QWidget *parent, const char *name,
00221                               bool handleAllApps )
00222     : KNotifyWidgetBase( parent, name ? name : "KNotifyWidget" )
00223 {
00224     d = new Private;
00225 
00226     m_allApps.setAutoDelete( true );
00227 
00228     if ( !handleAllApps )
00229     {
00230         m_affectAllApps->hide();
00231         m_playerButton->hide();
00232     }
00233 
00234     SelectionCombo::fill( m_comboEnable );
00235     SelectionCombo::fill( m_comboDisable );
00236 
00237     m_listview->setFullWidth( true );
00238     m_listview->setAllColumnsShowFocus( true );
00239 
00240     QPixmap pexec = SmallIcon("exec");
00241     QPixmap pstderr = SmallIcon("terminal");
00242     QPixmap pmessage = SmallIcon("info");
00243     QPixmap plogfile = SmallIcon("log");
00244     QPixmap psound = SmallIcon("sound");
00245     QPixmap ptaskbar = SmallIcon("kicker");
00246 
00247     d->pixmaps[COL_EXECUTE] = pexec;
00248     d->pixmaps[COL_STDERR]  = pstderr;
00249     d->pixmaps[COL_MESSAGE] = pmessage;
00250     d->pixmaps[COL_LOGFILE] = plogfile;
00251     d->pixmaps[COL_SOUND]   = psound;
00252     d->pixmaps[COL_TASKBAR] = ptaskbar;
00253 
00254     int w = KIcon::SizeSmall + 6;
00255 
00256     QHeader *header = m_listview->header();
00257     header->setLabel( COL_EXECUTE, pexec,    QString::null, w );
00258     header->setLabel( COL_STDERR,  pstderr,  QString::null, w );
00259     header->setLabel( COL_MESSAGE, pmessage, QString::null, w );
00260     header->setLabel( COL_LOGFILE, plogfile, QString::null, w );
00261     header->setLabel( COL_SOUND,   psound,   QString::null, w );
00262     header->setLabel( COL_TASKBAR, ptaskbar, QString::null, w );
00263 
00264     d->toolTip = new KNotifyToolTip( header );
00265 
00266     m_playButton->setIconSet( SmallIconSet( "player_play" ) );
00267     connect( m_playButton, SIGNAL( clicked() ), SLOT( playSound() ));
00268 
00269     connect( m_listview, SIGNAL( currentChanged( QListViewItem * ) ),
00270              SLOT( slotEventChanged( QListViewItem * ) ));
00271     connect( m_listview, SIGNAL(clicked( QListViewItem *, const QPoint&, int)),
00272              SLOT( slotItemClicked( QListViewItem *, const QPoint&, int )));
00273 
00274     connect( m_playSound, SIGNAL( toggled( bool )),
00275              SLOT( soundToggled( bool )) );
00276     connect( m_logToFile, SIGNAL( toggled( bool )),
00277              SLOT( loggingToggled( bool )) );
00278     connect( m_execute, SIGNAL( toggled( bool )),
00279              SLOT( executeToggled( bool )) );
00280     connect( m_messageBox, SIGNAL( toggled( bool )),
00281              SLOT( messageBoxChanged() ) );
00282     connect( m_passivePopup, SIGNAL( toggled( bool )),
00283              SLOT( messageBoxChanged() ) );
00284     connect( m_stderr, SIGNAL( toggled( bool )),
00285              SLOT( stderrToggled( bool ) ) );
00286     connect( m_taskbar, SIGNAL( toggled( bool )),
00287              SLOT( taskbarToggled( bool ) ) );
00288 
00289     connect( m_soundPath, SIGNAL( textChanged( const QString& )),
00290              SLOT( soundFileChanged( const QString& )));
00291     connect( m_logfilePath, SIGNAL( textChanged( const QString& )),
00292              SLOT( logfileChanged( const QString& ) ));
00293     connect( m_executePath, SIGNAL( textChanged( const QString& )),
00294              SLOT( commandlineChanged( const QString& ) ));
00295 
00296     connect( m_soundPath, SIGNAL( openFileDialog( KURLRequester * )),
00297              SLOT( openSoundDialog( KURLRequester * )));
00298     connect( m_logfilePath, SIGNAL( openFileDialog( KURLRequester * )),
00299              SLOT( openLogDialog( KURLRequester * )));
00300     connect( m_executePath, SIGNAL( openFileDialog( KURLRequester * )),
00301              SLOT( openExecDialog( KURLRequester * )));
00302 
00303     connect( m_extension, SIGNAL( clicked() ),
00304              SLOT( toggleAdvanced()) );
00305 
00306     connect( m_buttonEnable, SIGNAL( clicked() ), SLOT( enableAll() ));
00307     connect( m_buttonDisable, SIGNAL( clicked() ), SLOT( enableAll() ));
00308 
00309     QString whatsThis = i18n("<qt>You may use the following macros<br>"
00310         "in the commandline:<br>"
00311         "<b>%e</b>: for the event name,<br>"
00312         "<b>%a</b>: for the name of the application that sent the event,<br>"
00313         "<b>%s</b>: for the notification message,<br>"
00314         "<b>%w</b>: for the numeric window ID where the event originated,<br>"
00315         "<b>%i</b>: for the numeric event ID.");
00316     QWhatsThis::add( m_execute, whatsThis );
00317     QWhatsThis::add( m_executePath, whatsThis );
00318     
00319     showAdvanced( false );
00320 
00321     slotEventChanged( 0L ); // disable widgets by default
00322 }
00323 
00324 KNotifyWidget::~KNotifyWidget()
00325 {
00326     delete d->toolTip;
00327     delete d;
00328 }
00329 
00330 void KNotifyWidget::toggleAdvanced()
00331 {
00332     showAdvanced( m_logToFile->isHidden() );
00333 }
00334 
00335 void KNotifyWidget::showAdvanced( bool show )
00336 {
00337     if ( show )
00338     {
00339         m_extension->setText( i18n("Advanced <<") );
00340         QToolTip::add( m_extension, i18n("Hide advanced options") );
00341 
00342         m_logToFile->show();
00343         m_logfilePath->show();
00344         m_execute->show();
00345         m_executePath->show();
00346         m_messageBox->show();
00347         m_passivePopup->show();
00348         m_stderr->show();
00349         m_taskbar->show();
00350 
00351     m_passivePopup->setEnabled( m_messageBox->isChecked() );
00352         m_actionsBoxLayout->setSpacing( KDialog::spacingHint() );
00353     }
00354     else
00355     {
00356         m_extension->setText( i18n("Advanced >>") );
00357         QToolTip::add( m_extension, i18n("Show advanced options") );
00358 
00359         m_logToFile->hide();
00360         m_logfilePath->hide();
00361         m_execute->hide();
00362         m_executePath->hide();
00363         m_messageBox->hide();
00364         m_passivePopup->hide();
00365         m_stderr->hide();
00366         m_taskbar->hide();
00367 
00368         m_actionsBoxLayout->setSpacing( 0 );
00369     }
00370 }
00371 
00372 Application * KNotifyWidget::addApplicationEvents( const QString& path )
00373 {
00374     kdDebug() << "**** knotify: adding path: " << path << endl;
00375     QString relativePath = path;
00376 
00377     if ( path.at(0) == '/' && KStandardDirs::exists( path ) )
00378         relativePath = makeRelative( path );
00379 
00380     if ( !relativePath.isEmpty() )
00381     {
00382         Application *app = new Application( relativePath );
00383         m_allApps.append( app );
00384         return app;
00385     }
00386 
00387     return 0L;
00388 }
00389 
00390 void KNotifyWidget::clear()
00391 {
00392     clearVisible();
00393     m_allApps.clear();
00394 }
00395 
00396 void KNotifyWidget::clearVisible()
00397 {
00398     m_visibleApps.clear();
00399     m_listview->clear();
00400     slotEventChanged( 0L ); // disable widgets
00401 }
00402 
00403 void KNotifyWidget::showEvent( QShowEvent *e )
00404 {
00405     selectItem( m_listview->firstChild() );
00406     KNotifyWidgetBase::showEvent( e );
00407 }
00408 
00409 void KNotifyWidget::slotEventChanged( QListViewItem *item )
00410 {
00411     bool on = (item != 0L);
00412 
00413     m_actionsBox->setEnabled( on );
00414     m_controlsBox->setEnabled( on );
00415 
00416     if ( !on )
00417         return;
00418 
00419     ListViewItem *lit = static_cast<ListViewItem*>( item );
00420     updateWidgets( lit );
00421 }
00422 
00423 void KNotifyWidget::updateWidgets( ListViewItem *item )
00424 {
00425     bool enable;
00426     bool checked;
00427 
00428     blockSignals( true ); // don't emit changed() signals
00429 
00430     const Event& event = item->event();
00431 
00432     // sound settings
00433     m_playButton->setEnabled( !event.soundfile.isEmpty() );
00434     m_soundPath->setURL( event.soundfile );
00435     enable = (event.dontShow & KNotifyClient::Sound) == 0;
00436     checked = enable && !event.soundfile.isEmpty() &&
00437               (event.presentation & KNotifyClient::Sound);
00438     m_playSound->setEnabled( enable );
00439     m_playSound->setChecked( checked );
00440     m_soundPath->setEnabled( checked );
00441 
00442 
00443     // logfile settings
00444     m_logfilePath->setURL( event.logfile );
00445     enable = (event.dontShow & KNotifyClient::Logfile) == 0;
00446     checked = enable && !event.logfile.isEmpty()  &&
00447               (event.presentation & KNotifyClient::Logfile);
00448     m_logToFile->setEnabled( enable );
00449     m_logToFile->setChecked( checked );
00450     m_logfilePath->setEnabled( checked );
00451 
00452 
00453     // execute program settings
00454     m_executePath->setURL( event.commandline );
00455     enable = (event.dontShow & KNotifyClient::Execute) == 0;
00456     checked = enable && !event.commandline.isEmpty() &&
00457               (event.presentation & KNotifyClient::Execute);
00458     m_execute->setEnabled( enable );
00459     m_execute->setChecked( checked );
00460     m_executePath->setEnabled( checked );
00461 
00462 
00463     // other settings
00464     m_messageBox->setChecked(event.presentation & (KNotifyClient::Messagebox | KNotifyClient::PassivePopup));
00465     enable = (event.dontShow & KNotifyClient::Messagebox) == 0;
00466     m_messageBox->setEnabled( enable );
00467 
00468     m_passivePopup->setChecked(event.presentation & KNotifyClient::PassivePopup);
00469     enable = (event.dontShow & KNotifyClient::PassivePopup) == 0;
00470     m_passivePopup->setEnabled( enable );
00471 
00472     m_stderr->setChecked( event.presentation & KNotifyClient::Stderr );
00473     enable = (event.dontShow & KNotifyClient::Stderr) == 0;
00474     m_stderr->setEnabled( enable );
00475 
00476     m_taskbar->setChecked(event.presentation & KNotifyClient::Taskbar);
00477     enable = (event.dontShow & KNotifyClient::Taskbar) == 0;
00478     m_taskbar->setEnabled( enable );
00479 
00480     updatePixmaps( item );
00481 
00482     blockSignals( false );
00483 }
00484 
00485 void KNotifyWidget::updatePixmaps( ListViewItem *item )
00486 {
00487     QPixmap emptyPix;
00488     Event &event = item->event();
00489 
00490     bool doIt = (event.presentation & KNotifyClient::Execute) &&
00491                 !event.commandline.isEmpty();
00492     item->setPixmap( COL_EXECUTE, doIt ? d->pixmaps[COL_EXECUTE] : emptyPix );
00493 
00494     doIt = (event.presentation & KNotifyClient::Sound) &&
00495            !event.soundfile.isEmpty();
00496     item->setPixmap( COL_SOUND, doIt ? d->pixmaps[COL_SOUND] : emptyPix );
00497 
00498     doIt = (event.presentation & KNotifyClient::Logfile) &&
00499            !event.logfile.isEmpty();
00500     item->setPixmap( COL_LOGFILE, doIt ? d->pixmaps[COL_LOGFILE] : emptyPix );
00501 
00502     item->setPixmap( COL_MESSAGE,
00503                      (event.presentation &
00504                       (KNotifyClient::Messagebox | KNotifyClient::PassivePopup)) ?
00505                      d->pixmaps[COL_MESSAGE] : emptyPix );
00506 
00507     item->setPixmap( COL_STDERR,
00508                      (event.presentation & KNotifyClient::Stderr) ?
00509                      d->pixmaps[COL_STDERR] : emptyPix );
00510     item->setPixmap( COL_TASKBAR,
00511                      (event.presentation & KNotifyClient::Taskbar) ?
00512                      d->pixmaps[COL_TASKBAR] : emptyPix );
00513 }
00514 
00515 void KNotifyWidget::addVisibleApp( Application *app )
00516 {
00517     if ( !app || (m_visibleApps.findRef( app ) != -1) )
00518         return;
00519 
00520     m_visibleApps.append( app );
00521     addToView( app->eventList() );
00522 
00523     QListViewItem *item = m_listview->selectedItem();
00524     if ( !item )
00525         item = m_listview->firstChild();
00526 
00527     selectItem( item );
00528 }
00529 
00530 void KNotifyWidget::addToView( const EventList& events )
00531 {
00532     ListViewItem *item = 0L;
00533 
00534     EventListIterator it( events );
00535 
00536     for ( ; it.current(); ++it )
00537     {
00538         Event *event = it.current();
00539         item = new ListViewItem( m_listview, event );
00540 
00541         if ( (event->presentation & KNotifyClient::Execute) &&
00542              !event->commandline.isEmpty() )
00543             item->setPixmap( COL_EXECUTE, d->pixmaps[COL_EXECUTE] );
00544         if ( (event->presentation & KNotifyClient::Sound) &&
00545              !event->soundfile.isEmpty() )
00546             item->setPixmap( COL_SOUND, d->pixmaps[COL_SOUND] );
00547         if ( (event->presentation & KNotifyClient::Logfile) &&
00548              !event->logfile.isEmpty() )
00549             item->setPixmap( COL_LOGFILE, d->pixmaps[COL_LOGFILE] );
00550         if ( event->presentation & (KNotifyClient::Messagebox|KNotifyClient::PassivePopup) )
00551             item->setPixmap( COL_MESSAGE, d->pixmaps[COL_MESSAGE] );
00552         if ( event->presentation & KNotifyClient::Stderr )
00553             item->setPixmap( COL_STDERR, d->pixmaps[COL_STDERR] );
00554         if ( event->presentation & KNotifyClient::Taskbar )
00555             item->setPixmap( COL_TASKBAR, d->pixmaps[COL_TASKBAR] );
00556     }
00557 }
00558 
00559 void KNotifyWidget::widgetChanged( QListViewItem *item,
00560                                    int what, bool on, QWidget *buddy )
00561 {
00562     if ( signalsBlocked() )
00563         return;
00564 
00565     if ( buddy )
00566         buddy->setEnabled( on );
00567 
00568     Event &e = static_cast<ListViewItem*>( item )->event();
00569     if ( on )
00570     {
00571         e.presentation |= what;
00572         if ( buddy )
00573             buddy->setFocus();
00574     }
00575     else
00576         e.presentation &= ~what;
00577 
00578     emit changed( true );
00579 }
00580 
00581 void KNotifyWidget::soundToggled( bool on )
00582 {
00583     QListViewItem *item = m_listview->currentItem();
00584     if ( !item )
00585         return;
00586     bool doIcon = on && !m_soundPath->url().isEmpty();
00587     item->setPixmap( COL_SOUND, doIcon ? d->pixmaps[COL_SOUND] : QPixmap() );
00588     widgetChanged( item, KNotifyClient::Sound, on, m_soundPath );
00589 }
00590 
00591 void KNotifyWidget::loggingToggled( bool on )
00592 {
00593     QListViewItem *item = m_listview->currentItem();
00594     if ( !item )
00595         return;
00596     bool doIcon = on && !m_logfilePath->url().isEmpty();
00597     item->setPixmap(COL_LOGFILE, doIcon ? d->pixmaps[COL_LOGFILE] : QPixmap());
00598     widgetChanged( item, KNotifyClient::Logfile, on, m_logfilePath );
00599 }
00600 
00601 void KNotifyWidget::executeToggled( bool on )
00602 {
00603     QListViewItem *item = m_listview->currentItem();
00604     if ( !item )
00605         return;
00606     bool doIcon = on && !m_executePath->url().isEmpty();
00607     item->setPixmap(COL_EXECUTE, doIcon ? d->pixmaps[COL_EXECUTE] : QPixmap());
00608     widgetChanged( item, KNotifyClient::Execute, on, m_executePath );
00609 }
00610 
00611 void KNotifyWidget::messageBoxChanged()
00612 {
00613     if ( signalsBlocked() )
00614         return;
00615 
00616     m_passivePopup->setEnabled( m_messageBox->isChecked() );
00617 
00618     QListViewItem *item = m_listview->currentItem();
00619     if ( !item )
00620         return;
00621 
00622     bool on = m_passivePopup->isEnabled();
00623     item->setPixmap( COL_MESSAGE, on ? d->pixmaps[COL_MESSAGE] : QPixmap() );
00624 
00625     Event &e = static_cast<ListViewItem*>( item )->event();
00626 
00627     if ( m_messageBox->isChecked() ) {
00628     if ( m_passivePopup->isChecked() ) {
00629         e.presentation |= KNotifyClient::PassivePopup;
00630         e.presentation &= ~KNotifyClient::Messagebox;
00631     }
00632     else {
00633         e.presentation &= ~KNotifyClient::PassivePopup;
00634         e.presentation |= KNotifyClient::Messagebox;
00635     }
00636     }
00637     else {
00638         e.presentation &= ~KNotifyClient::Messagebox;
00639         e.presentation &= ~KNotifyClient::PassivePopup;
00640     }
00641 
00642     emit changed( true );
00643 }
00644 
00645 void KNotifyWidget::stderrToggled( bool on )
00646 {
00647     QListViewItem *item = m_listview->currentItem();
00648     if ( !item )
00649         return;
00650     item->setPixmap( COL_STDERR, on ? d->pixmaps[COL_STDERR] : QPixmap() );
00651     widgetChanged( item, KNotifyClient::Stderr, on );
00652 }
00653 
00654 void KNotifyWidget::taskbarToggled( bool on )
00655 {
00656     QListViewItem *item = m_listview->currentItem();
00657     if ( !item )
00658         return;
00659     item->setPixmap( COL_TASKBAR, on ? d->pixmaps[COL_TASKBAR] : QPixmap() );
00660     widgetChanged( item, KNotifyClient::Taskbar, on );
00661 }
00662 
00663 void KNotifyWidget::soundFileChanged( const QString& text )
00664 {
00665     if ( signalsBlocked() )
00666         return;
00667 
00668     QListViewItem *item = m_listview->currentItem();
00669     if ( !item )
00670         return;
00671 
00672     m_playButton->setEnabled( !text.isEmpty() );
00673 
00674     currentEvent()->soundfile = text;
00675     bool ok = !text.isEmpty() && m_playSound->isChecked();
00676     item->setPixmap( COL_SOUND, ok ? d->pixmaps[COL_SOUND] : QPixmap() );
00677 
00678     emit changed( true );
00679 }
00680 
00681 void KNotifyWidget::logfileChanged( const QString& text )
00682 {
00683     if ( signalsBlocked() )
00684         return;
00685 
00686     QListViewItem *item = m_listview->currentItem();
00687     if ( !item )
00688         return;
00689 
00690     currentEvent()->logfile = text;
00691     bool ok = !text.isEmpty() && m_logToFile->isChecked();
00692     item->setPixmap( COL_LOGFILE, ok ? d->pixmaps[COL_LOGFILE] : QPixmap() );
00693 
00694     emit changed( true );
00695 }
00696 
00697 void KNotifyWidget::commandlineChanged( const QString& text )
00698 {
00699     if ( signalsBlocked() )
00700         return;
00701 
00702     QListViewItem *item = m_listview->currentItem();
00703     if ( !item )
00704         return;
00705 
00706     currentEvent()->commandline = text;
00707     bool ok = !text.isEmpty() && m_execute->isChecked();
00708     item->setPixmap( COL_EXECUTE, ok ? d->pixmaps[COL_EXECUTE] : QPixmap() );
00709 
00710     emit changed( true );
00711 }
00712 
00713 void KNotifyWidget::slotItemClicked( QListViewItem *item, const QPoint&,
00714                                      int col )
00715 {
00716     if ( !item || !item->isSelected() )
00717         return;
00718 
00719     Event *event = currentEvent();
00720     if ( !event )
00721         return; // very unlikely, but safety first
00722 
00723     bool doShowAdvanced = false;
00724 
00725     switch( col )
00726     {
00727         case COL_EXECUTE:
00728             m_execute->toggle();
00729             m_executePath->setFocus();
00730             doShowAdvanced = true;
00731             break;
00732         case COL_STDERR:
00733             m_stderr->toggle();
00734             break;
00735         case COL_TASKBAR:
00736             m_taskbar->toggle();
00737             break;
00738         case COL_MESSAGE:
00739             m_passivePopup->setChecked( true ); // default to passive popups
00740             m_messageBox->toggle();
00741             break;
00742         case COL_LOGFILE:
00743             m_logToFile->toggle();
00744             m_logfilePath->setFocus();
00745             doShowAdvanced = true;
00746             break;
00747         case COL_SOUND:
00748             m_playSound->toggle();
00749             break;
00750         default: // do nothing
00751             break;
00752     }
00753 
00754     if ( doShowAdvanced && !m_logToFile->isVisible() )
00755     {
00756         showAdvanced( true );
00757         m_listview->ensureItemVisible( m_listview->currentItem() );
00758     }
00759 }
00760 
00761 void KNotifyWidget::sort( bool ascending )
00762 {
00763     m_listview->setSorting( COL_EVENT, ascending );
00764     m_listview->sort();
00765 }
00766 
00767 void KNotifyWidget::selectItem( QListViewItem *item )
00768 {
00769     if ( item )
00770     {
00771         m_listview->setCurrentItem( item );
00772         item->setSelected( true );
00773         slotEventChanged( item );
00774     }
00775 }
00776 
00777 void KNotifyWidget::resetDefaults( bool ask )
00778 {
00779     if ( ask )
00780     {
00781         if ( KMessageBox::warningContinueCancel(this,
00782                                    i18n("This will cause the notifications "
00783                                         "to be reset to their defaults."),
00784                                                 i18n("Are You Sure?"),
00785                                                 i18n("&Reset"))
00786              != KMessageBox::Continue)
00787             return;
00788     }
00789 
00790     reload( true ); // defaults
00791     emit changed( true );
00792 }
00793 
00794 void KNotifyWidget::reload( bool revertToDefaults )
00795 {
00796     m_listview->clear();
00797     ApplicationListIterator it( m_visibleApps );
00798     for ( ; it.current(); ++it )
00799     {
00800         it.current()->reloadEvents( revertToDefaults );
00801         addToView( it.current()->eventList() );
00802     }
00803 
00804     m_listview->sort();
00805     selectItem( m_listview->firstChild()  );
00806 }
00807 
00808 void KNotifyWidget::save()
00809 {
00810     kdDebug() << "save\n";
00811 
00812     ApplicationListIterator it( m_allApps );
00813     while ( it.current() )
00814     {
00815         (*it)->save();
00816         ++it;
00817     }
00818 
00819     if ( kapp )
00820     {
00821         if ( !kapp->dcopClient()->isAttached() )
00822             kapp->dcopClient()->attach();
00823         kapp->dcopClient()->send("knotify", "", "reconfigure()", "");
00824     }
00825 
00826     emit changed( false );
00827 }
00828 
00829 // returns e.g. "kwin/eventsrc" from a given path
00830 // "/opt/kde3/share/apps/kwin/eventsrc"
00831 QString KNotifyWidget::makeRelative( const QString& fullPath )
00832 {
00833     int slash = fullPath.findRev( '/' ) - 1;
00834     slash = fullPath.findRev( '/', slash );
00835 
00836     if ( slash < 0 )
00837         return QString::null;
00838 
00839     return fullPath.mid( slash+1 );
00840 }
00841 
00842 Event * KNotifyWidget::currentEvent()
00843 {
00844     QListViewItem *current = m_listview->currentItem();
00845     if ( !current )
00846         return 0L;
00847 
00848     return &static_cast<ListViewItem*>( current )->event();
00849 }
00850 
00851 void KNotifyWidget::openSoundDialog( KURLRequester *requester )
00852 {
00853     // only need to init this once
00854     requester->disconnect( SIGNAL( openFileDialog( KURLRequester * )),
00855                            this, SLOT( openSoundDialog( KURLRequester * )));
00856 
00857     KFileDialog *fileDialog = requester->fileDialog();
00858     fileDialog->setCaption( i18n("Select Sound File") );
00859     QStringList filters;
00860     filters << "audio/x-wav" << "audio/x-mp3" << "application/ogg"
00861             << "audio/x-adpcm";
00862     fileDialog->setMimeFilter( filters );
00863 
00864     // find the first "sound"-resource that contains files
00865     const Application *app = currentEvent()->application();
00866     QStringList soundDirs =
00867         KGlobal::dirs()->findDirs("data", app->appName() + "/sounds");
00868     soundDirs += KGlobal::dirs()->resourceDirs( "sound" );
00869 
00870     if ( !soundDirs.isEmpty() ) {
00871         KURL soundURL;
00872         QDir dir;
00873         dir.setFilter( QDir::Files | QDir::Readable );
00874         QStringList::ConstIterator it = soundDirs.begin();
00875         while ( it != soundDirs.end() ) {
00876             dir = *it;
00877             if ( dir.isReadable() && dir.count() > 2 ) {
00878                 soundURL.setPath( *it );
00879                 fileDialog->setURL( soundURL );
00880                 break;
00881             }
00882             ++it;
00883         }
00884     }
00885 }
00886 
00887 void KNotifyWidget::openLogDialog( KURLRequester *requester )
00888 {
00889     // only need to init this once
00890     requester->disconnect( SIGNAL( openFileDialog( KURLRequester * )),
00891                            this, SLOT( openLogDialog( KURLRequester * )));
00892 
00893     KFileDialog *fileDialog = requester->fileDialog();
00894     fileDialog->setCaption( i18n("Select Log File") );
00895     QStringList filters;
00896     filters << "text/x-log" << "text/plain";
00897     fileDialog->setMimeFilter( filters );
00898 }
00899 
00900 void KNotifyWidget::openExecDialog( KURLRequester *requester )
00901 {
00902     // only need to init this once
00903     requester->disconnect( SIGNAL( openFileDialog( KURLRequester * )),
00904                            this, SLOT( openExecDialog( KURLRequester * )));
00905 
00906 
00907     KFileDialog *fileDialog = requester->fileDialog();
00908     fileDialog->setCaption( i18n("Select File to Execute") );
00909     QStringList filters;
00910     filters << "application/x-executable" << "application/x-shellscript"
00911             << "application/x-perl" << "application/x-python";
00912     fileDialog->setMimeFilter( filters );
00913 }
00914 
00915 void KNotifyWidget::playSound()
00916 {
00917     if (!KIO::NetAccess::exists( m_soundPath->url(), true, 0 )) {        
00918         bool foundSound=false;
00919 
00920         // find the first "sound"-resource that contains files
00921         const Application *app = currentEvent()->application();
00922         QStringList soundDirs = KGlobal::dirs()->findDirs("data", app->appName() + "/sounds");
00923         soundDirs += KGlobal::dirs()->resourceDirs( "sound" );
00924 
00925         if ( !soundDirs.isEmpty() ) {
00926            QDir dir;
00927            dir.setFilter( QDir::Files | QDir::Readable );
00928            QStringList::ConstIterator it = soundDirs.begin();
00929            while ( it != soundDirs.end() ) {
00930                dir = *it;
00931                if ( dir.isReadable() && dir.count() > 2 && 
00932                 KIO::NetAccess::exists( *it + m_soundPath->url(), true, 0 )) {
00933                        foundSound=true;
00934                        break;
00935                }
00936                ++it;
00937            }
00938         }
00939         if ( !foundSound ) {
00940             KMessageBox::sorry(this, i18n("The specified file does not exist." ));
00941             return;
00942         }
00943     }
00944     KAudioPlayer::play( m_soundPath->url() );
00945 }
00946 
00947 void KNotifyWidget::enableAll()
00948 {
00949     bool enable = (sender() == m_buttonEnable);
00950     enableAll( SelectionCombo::type(enable ? m_comboEnable : m_comboDisable),
00951                enable );
00952 }
00953 
00954 void KNotifyWidget::enableAll( int what, bool enable )
00955 {
00956     if ( m_listview->childCount() == 0 )
00957         return;
00958 
00959     bool affectAll = m_affectAllApps->isChecked(); // multi-apps mode
00960 
00961     ApplicationListIterator appIt( affectAll ? m_allApps : m_visibleApps );
00962     for ( ; appIt.current(); ++appIt )
00963     {
00964         const EventList& events = appIt.current()->eventList();
00965         EventListIterator it( events );
00966         for ( ; it.current(); ++it )
00967         {
00968             if ( enable )
00969                 it.current()->presentation |= what;
00970             else
00971                 it.current()->presentation &= ~what;
00972         }
00973     }
00974 
00975     // now make the listview reflect the changes
00976     QListViewItemIterator it( m_listview->firstChild() );
00977     for ( ; it.current(); ++it )
00978     {
00979         ListViewItem *item = static_cast<ListViewItem*>( it.current() );
00980         updatePixmaps( item );
00981     }
00982 
00983     QListViewItem *item = m_listview->currentItem();
00984     if ( !item )
00985         item = m_listview->firstChild();
00986     selectItem( item );
00987 
00988     emit changed( true );
00989 }
00990 
00991 
00994 
00995 
00996 //
00997 // path must be "appname/eventsrc", i.e. a relative path
00998 //
00999 Application::Application( const QString &path )
01000 {
01001     QString config_file = path;
01002     config_file[config_file.find('/')] = '.';
01003     m_events = 0L;
01004     config = new KConfig(config_file, false, false);
01005     kc = new KConfig(path, true, false, "data");
01006     kc->setGroup( QString::fromLatin1("!Global!") );
01007     m_icon = kc->readEntry(QString::fromLatin1("IconName"),
01008                            QString::fromLatin1("misc"));
01009     m_description = kc->readEntry( QString::fromLatin1("Comment"),
01010                                    i18n("No description available") );
01011 
01012     int index = path.find( '/' );
01013     if ( index >= 0 )
01014         m_appname = path.left( index );
01015     else
01016         kdDebug() << "Cannot determine application name from path: " << path << endl;
01017 }
01018 
01019 Application::~Application()
01020 {
01021     delete config;
01022     delete kc;
01023     delete m_events;
01024 }
01025 
01026 
01027 const EventList&  Application::eventList()
01028 {
01029     if ( !m_events ) {
01030         m_events = new EventList;
01031         m_events->setAutoDelete( true );
01032         reloadEvents();
01033     }
01034 
01035     return *m_events;
01036 }
01037 
01038 
01039 void Application::save()
01040 {
01041     if ( !m_events )
01042         return;
01043 
01044     EventListIterator it( *m_events );
01045     Event *e;
01046     while ( (e = it.current()) ) {
01047         config->setGroup( e->configGroup );
01048         config->writeEntry( "presentation", e->presentation );
01049         config->writePathEntry( "soundfile", e->soundfile );
01050         config->writePathEntry( "logfile", e->logfile );
01051         config->writePathEntry( "commandline", e->commandline );
01052 
01053         ++it;
01054     }
01055     config->sync();
01056 }
01057 
01058 
01059 void Application::reloadEvents( bool revertToDefaults )
01060 {
01061     if ( m_events )
01062         m_events->clear();
01063     else
01064     {
01065         m_events = new EventList;
01066         m_events->setAutoDelete( true );
01067     }
01068 
01069     Event *e = 0L;
01070 
01071     QString global = QString::fromLatin1("!Global!");
01072     QString default_group = QString::fromLatin1("<default>");
01073     QString name = QString::fromLatin1("Name");
01074     QString comment = QString::fromLatin1("Comment");
01075 
01076     QStringList conflist = kc->groupList();
01077     QStringList::ConstIterator it = conflist.begin();
01078 
01079     while ( it != conflist.end() ) {
01080         if ( (*it) != global && (*it) != default_group ) { // event group
01081             kc->setGroup( *it );
01082 
01083             e = new Event( this );
01084             e->name = kc->readEntry( name );
01085             e->description = kc->readEntry( comment );
01086             e->dontShow = kc->readNumEntry("nopresentation", 0 );
01087             e->configGroup = *it;
01088             if ( e->name.isEmpty() && e->description.isEmpty() )
01089                 delete e;
01090             else { // load the event
01091                 if( !e->name.isEmpty() && e->description.isEmpty() )
01092                         e->description = e->name;
01093                 // default to passive popups over plain messageboxes
01094                 int default_rep = kc->readNumEntry("default_presentation",
01095                                                    0 | KNotifyClient::PassivePopup);
01096                 QString default_logfile = kc->readPathEntry("default_logfile");
01097                 QString default_soundfile = kc->readPathEntry("default_sound");
01098                 QString default_commandline = kc->readPathEntry("default_commandline");
01099 
01100                 config->setGroup(*it);
01101 
01102                 if ( revertToDefaults )
01103                 {
01104                     e->presentation = default_rep;
01105                     e->logfile = default_logfile;
01106                     e->soundfile = default_soundfile;
01107                     e->commandline = default_commandline;
01108                 }
01109 
01110                 else
01111                 {
01112                     e->presentation = config->readNumEntry("presentation",
01113                                                            default_rep);
01114                     e->logfile = config->readPathEntry("logfile",
01115                                                    default_logfile);
01116                     e->soundfile = config->readPathEntry("soundfile",
01117                                                      default_soundfile);
01118                     e->commandline = config->readPathEntry("commandline",
01119                                                        default_commandline);
01120                 }
01121 
01122                 m_events->append( e );
01123             }
01124         }
01125 
01126         ++it;
01127     }
01128 
01129     return;
01130 }
01131 
01134 
01135 ListViewItem::ListViewItem( QListView *view, Event *event )
01136     : QListViewItem( view ),
01137       m_event( event )
01138 {
01139     setText( COL_EVENT, event->text() );
01140 }
01141 
01142 int ListViewItem::compare ( QListViewItem * i, int col, bool ascending ) const
01143 {
01144     ListViewItem *item = static_cast<ListViewItem*>( i );
01145     int myPres = m_event->presentation;
01146     int otherPres = item->event().presentation;
01147 
01148     int action = 0;
01149 
01150     switch ( col )
01151     {
01152         case COL_EVENT: // use default sorting
01153             return QListViewItem::compare( i, col, ascending );
01154 
01155         case COL_EXECUTE:
01156             action = KNotifyClient::Execute;
01157             break;
01158         case COL_LOGFILE:
01159             action = KNotifyClient::Logfile;
01160             break;
01161         case COL_MESSAGE:
01162             action = (KNotifyClient::Messagebox | KNotifyClient::PassivePopup);
01163             break;
01164         case COL_SOUND:
01165             action = KNotifyClient::Sound;
01166             break;
01167         case COL_STDERR:
01168             action = KNotifyClient::Stderr;
01169             break;
01170         case COL_TASKBAR:
01171             action = KNotifyClient::Taskbar;
01172             break;
01173     }
01174 
01175     if ( (myPres & action) == (otherPres & action) )
01176     {
01177         // default sorting by event
01178         return QListViewItem::compare( i, COL_EVENT, true );
01179     }
01180 
01181     if ( myPres & action )
01182         return -1;
01183     if ( otherPres & action )
01184         return 1;
01185 
01186     return 0;
01187 }
01188 
01189 #include "knotifydialog.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys