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 QString soundPath = m_soundPath->url(); 00918 if (!KIO::NetAccess::exists( m_soundPath->url(), true, 0 )) { 00919 bool foundSound=false; 00920 00921 // find the first "sound"-resource that contains files 00922 const Application *app = currentEvent()->application(); 00923 QStringList soundDirs = KGlobal::dirs()->findDirs("data", app->appName() + "/sounds"); 00924 soundDirs += KGlobal::dirs()->resourceDirs( "sound" ); 00925 00926 if ( !soundDirs.isEmpty() ) { 00927 QDir dir; 00928 dir.setFilter( QDir::Files | QDir::Readable ); 00929 QStringList::ConstIterator it = soundDirs.begin(); 00930 while ( it != soundDirs.end() ) { 00931 dir = *it; 00932 if ( dir.isReadable() && dir.count() > 2 && 00933 KIO::NetAccess::exists( *it + m_soundPath->url(), true, 0 )) { 00934 foundSound=true; 00935 soundPath = *it + m_soundPath->url(); 00936 break; 00937 } 00938 ++it; 00939 } 00940 } 00941 if ( !foundSound ) { 00942 KMessageBox::sorry(this, i18n("The specified file does not exist." )); 00943 return; 00944 } 00945 } 00946 KAudioPlayer::play( soundPath ); 00947 } 00948 00949 void KNotifyWidget::enableAll() 00950 { 00951 bool enable = (sender() == m_buttonEnable); 00952 enableAll( SelectionCombo::type(enable ? m_comboEnable : m_comboDisable), 00953 enable ); 00954 } 00955 00956 void KNotifyWidget::enableAll( int what, bool enable ) 00957 { 00958 if ( m_listview->childCount() == 0 ) 00959 return; 00960 00961 bool affectAll = m_affectAllApps->isChecked(); // multi-apps mode 00962 00963 ApplicationListIterator appIt( affectAll ? m_allApps : m_visibleApps ); 00964 for ( ; appIt.current(); ++appIt ) 00965 { 00966 const EventList& events = appIt.current()->eventList(); 00967 EventListIterator it( events ); 00968 for ( ; it.current(); ++it ) 00969 { 00970 if ( enable ) 00971 it.current()->presentation |= what; 00972 else 00973 it.current()->presentation &= ~what; 00974 } 00975 } 00976 00977 // now make the listview reflect the changes 00978 QListViewItemIterator it( m_listview->firstChild() ); 00979 for ( ; it.current(); ++it ) 00980 { 00981 ListViewItem *item = static_cast<ListViewItem*>( it.current() ); 00982 updatePixmaps( item ); 00983 } 00984 00985 QListViewItem *item = m_listview->currentItem(); 00986 if ( !item ) 00987 item = m_listview->firstChild(); 00988 selectItem( item ); 00989 00990 emit changed( true ); 00991 } 00992 00993 00996 00997 00998 // 00999 // path must be "appname/eventsrc", i.e. a relative path 01000 // 01001 Application::Application( const QString &path ) 01002 { 01003 QString config_file = path; 01004 config_file[config_file.find('/')] = '.'; 01005 m_events = 0L; 01006 config = new KConfig(config_file, false, false); 01007 kc = new KConfig(path, true, false, "data"); 01008 kc->setGroup( QString::fromLatin1("!Global!") ); 01009 m_icon = kc->readEntry(QString::fromLatin1("IconName"), 01010 QString::fromLatin1("misc")); 01011 m_description = kc->readEntry( QString::fromLatin1("Comment"), 01012 i18n("No description available") ); 01013 01014 int index = path.find( '/' ); 01015 if ( index >= 0 ) 01016 m_appname = path.left( index ); 01017 else 01018 kdDebug() << "Cannot determine application name from path: " << path << endl; 01019 } 01020 01021 Application::~Application() 01022 { 01023 delete config; 01024 delete kc; 01025 delete m_events; 01026 } 01027 01028 01029 const EventList& Application::eventList() 01030 { 01031 if ( !m_events ) { 01032 m_events = new EventList; 01033 m_events->setAutoDelete( true ); 01034 reloadEvents(); 01035 } 01036 01037 return *m_events; 01038 } 01039 01040 01041 void Application::save() 01042 { 01043 if ( !m_events ) 01044 return; 01045 01046 EventListIterator it( *m_events ); 01047 Event *e; 01048 while ( (e = it.current()) ) { 01049 config->setGroup( e->configGroup ); 01050 config->writeEntry( "presentation", e->presentation ); 01051 config->writePathEntry( "soundfile", e->soundfile ); 01052 config->writePathEntry( "logfile", e->logfile ); 01053 config->writePathEntry( "commandline", e->commandline ); 01054 01055 ++it; 01056 } 01057 config->sync(); 01058 } 01059 01060 01061 void Application::reloadEvents( bool revertToDefaults ) 01062 { 01063 if ( m_events ) 01064 m_events->clear(); 01065 else 01066 { 01067 m_events = new EventList; 01068 m_events->setAutoDelete( true ); 01069 } 01070 01071 Event *e = 0L; 01072 01073 QString global = QString::fromLatin1("!Global!"); 01074 QString default_group = QString::fromLatin1("<default>"); 01075 QString name = QString::fromLatin1("Name"); 01076 QString comment = QString::fromLatin1("Comment"); 01077 01078 QStringList conflist = kc->groupList(); 01079 QStringList::ConstIterator it = conflist.begin(); 01080 01081 while ( it != conflist.end() ) { 01082 if ( (*it) != global && (*it) != default_group ) { // event group 01083 kc->setGroup( *it ); 01084 01085 e = new Event( this ); 01086 e->name = kc->readEntry( name ); 01087 e->description = kc->readEntry( comment ); 01088 e->dontShow = kc->readNumEntry("nopresentation", 0 ); 01089 e->configGroup = *it; 01090 if ( e->name.isEmpty() && e->description.isEmpty() ) 01091 delete e; 01092 else { // load the event 01093 if( !e->name.isEmpty() && e->description.isEmpty() ) 01094 e->description = e->name; 01095 // default to passive popups over plain messageboxes 01096 int default_rep = kc->readNumEntry("default_presentation", 01097 0 | KNotifyClient::PassivePopup); 01098 QString default_logfile = kc->readPathEntry("default_logfile"); 01099 QString default_soundfile = kc->readPathEntry("default_sound"); 01100 QString default_commandline = kc->readPathEntry("default_commandline"); 01101 01102 config->setGroup(*it); 01103 01104 if ( revertToDefaults ) 01105 { 01106 e->presentation = default_rep; 01107 e->logfile = default_logfile; 01108 e->soundfile = default_soundfile; 01109 e->commandline = default_commandline; 01110 } 01111 01112 else 01113 { 01114 e->presentation = config->readNumEntry("presentation", 01115 default_rep); 01116 e->logfile = config->readPathEntry("logfile", 01117 default_logfile); 01118 e->soundfile = config->readPathEntry("soundfile", 01119 default_soundfile); 01120 e->commandline = config->readPathEntry("commandline", 01121 default_commandline); 01122 } 01123 01124 m_events->append( e ); 01125 } 01126 } 01127 01128 ++it; 01129 } 01130 01131 return; 01132 } 01133 01136 01137 ListViewItem::ListViewItem( QListView *view, Event *event ) 01138 : QListViewItem( view ), 01139 m_event( event ) 01140 { 01141 setText( COL_EVENT, event->text() ); 01142 } 01143 01144 int ListViewItem::compare ( QListViewItem * i, int col, bool ascending ) const 01145 { 01146 ListViewItem *item = static_cast<ListViewItem*>( i ); 01147 int myPres = m_event->presentation; 01148 int otherPres = item->event().presentation; 01149 01150 int action = 0; 01151 01152 switch ( col ) 01153 { 01154 case COL_EVENT: // use default sorting 01155 return QListViewItem::compare( i, col, ascending ); 01156 01157 case COL_EXECUTE: 01158 action = KNotifyClient::Execute; 01159 break; 01160 case COL_LOGFILE: 01161 action = KNotifyClient::Logfile; 01162 break; 01163 case COL_MESSAGE: 01164 action = (KNotifyClient::Messagebox | KNotifyClient::PassivePopup); 01165 break; 01166 case COL_SOUND: 01167 action = KNotifyClient::Sound; 01168 break; 01169 case COL_STDERR: 01170 action = KNotifyClient::Stderr; 01171 break; 01172 case COL_TASKBAR: 01173 action = KNotifyClient::Taskbar; 01174 break; 01175 } 01176 01177 if ( (myPres & action) == (otherPres & action) ) 01178 { 01179 // default sorting by event 01180 return QListViewItem::compare( i, COL_EVENT, true ); 01181 } 01182 01183 if ( myPres & action ) 01184 return -1; 01185 if ( otherPres & action ) 01186 return 1; 01187 01188 return 0; 01189 } 01190 01191 #include "knotifydialog.moc"