2 * Copyright 2001 Stefan Schimanski <1Stein@gmx.de>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24 #include <klineedit.h>
25 #include <kiconloader.h>
26 #include <kapplication.h>
27 #include <kfiledialog.h>
29 #include <ktoolinvocation.h>
30 #include <kstandardguiitem.h>
32 #include <kstandardaction.h>
33 #include "kstatusnotifieritem.h"
35 class KTimerJobItem : public QTreeWidgetItem {
37 KTimerJobItem( KTimerJob *job, QTreeWidget *parent )
39 parent->addTopLevelItem(this);
45 KTimerJobItem( KTimerJob *job, QTreeWidget * parent, QTreeWidgetItem *after )
47 int otherItemIndex = parent->indexOfTopLevelItem(after);
48 parent->insertTopLevelItem(otherItemIndex + 1, this);
54 virtual ~KTimerJobItem() {
58 KTimerJob *job() { return m_job; }
60 void setStatus( bool error ) {
66 setText( 0, m_job->formatTime(m_job->value()) );
69 setIcon( 0, KIcon( QLatin1String( "process-stop" )) );
71 setIcon( 0, QPixmap() );
73 setText( 1, m_job->formatTime(m_job->delay()) );
75 switch( m_job->state() ) {
76 case KTimerJob::Stopped: setIcon( 2, KIcon( QLatin1String( "media-playback-stop" )) ); break;
77 case KTimerJob::Paused: setIcon( 2, KIcon( QLatin1String( "media-playback-pause" )) ); break;
78 case KTimerJob::Started: setIcon( 2, KIcon( QLatin1String( "arrow-right" )) ); break;
81 setText( 3, m_job->command() );
90 /***************************************************************/
93 struct KTimerPrefPrivate
95 QList<KTimerJob *> jobs;
98 KTimerPref::KTimerPref( QWidget *parent)
101 d = new KTimerPrefPrivate;
106 m_stop->setIcon( KIcon( QLatin1String( "media-playback-stop" )) );
107 m_pause->setIcon( KIcon( QLatin1String( "media-playback-pause" )) );
108 m_start->setIcon( KIcon( QLatin1String( "arrow-right" )) );
111 KStatusNotifierItem *tray = new KStatusNotifierItem(this);
112 tray->setIconByName(QLatin1String( "ktimer" ));
113 tray->setCategory(KStatusNotifierItem::ApplicationStatus);
114 tray->setStatus(KStatusNotifierItem::Active);
115 // set help button gui item
116 m_help->setGuiItem(KStandardGuiItem::help());
119 KAction *exit = KStandardAction::quit(this, SLOT(exit()), this);
123 connect( m_add, SIGNAL(clicked()), SLOT(add()) );
124 connect( m_remove, SIGNAL(clicked()), SLOT(remove()) );
125 connect( m_help, SIGNAL(clicked()), SLOT(help()) );
126 connect( m_list, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)),
127 SLOT(currentChanged(QTreeWidgetItem*,QTreeWidgetItem*)) );
128 loadJobs( KGlobal::config().data() );
134 KTimerPref::~KTimerPref()
139 void KTimerPref::saveAllJobs() {
140 saveJobs( KGlobal::config().data() );
144 void KTimerPref::add()
146 KTimerJob *job = new KTimerJob;
147 KTimerJobItem *item = new KTimerJobItem( job, m_list );
149 connect( job, SIGNAL(delayChanged(KTimerJob*,uint)),
150 SLOT(jobChanged(KTimerJob*)) );
151 connect( job, SIGNAL(valueChanged(KTimerJob*,uint)),
152 SLOT(jobChanged(KTimerJob*)) );
153 connect( job, SIGNAL(stateChanged(KTimerJob*,States)),
154 SLOT(jobChanged(KTimerJob*)) );
155 connect( job, SIGNAL(commandChanged(KTimerJob*,QString)),
156 SLOT(jobChanged(KTimerJob*)) );
157 connect( job, SIGNAL(finished(KTimerJob*,bool)),
158 SLOT(jobFinished(KTimerJob*,bool)) );
160 job->setUser( item );
162 // Qt drops currentChanged signals on first item (bug?)
163 if( m_list->topLevelItemCount()==1 )
164 currentChanged( item , NULL);
166 m_list->setCurrentItem( item );
171 void KTimerPref::remove()
173 delete m_list->currentItem();
177 void KTimerPref::help()
179 KToolInvocation::invokeHelp();
182 // note, don't use old, but added it so we can connect to the new one
183 void KTimerPref::currentChanged( QTreeWidgetItem *i , QTreeWidgetItem * /* old */)
185 KTimerJobItem *item = static_cast<KTimerJobItem*>(i);
187 KTimerJob *job = item->job();
189 m_state->setEnabled( true );
190 m_settings->setEnabled( true );
191 m_remove->setEnabled( true );
192 m_delayH->disconnect();
193 m_delayM->disconnect();
194 m_delay->disconnect();
195 m_loop->disconnect();
197 m_start->disconnect();
198 m_pause->disconnect();
199 m_stop->disconnect();
200 m_counter->disconnect();
201 m_slider->disconnect();
202 m_commandLine->disconnect();
203 m_commandLine->lineEdit()->disconnect();
205 // Set hour, minute and second QSpinBoxes before we connect to signals.
207 job->secondsToHMS( job->delay(), &h, &m, &s );
208 m_delayH->setValue( h );
209 m_delayM->setValue( m );
210 m_delay->setValue( s );
212 connect( m_commandLine->lineEdit(), SIGNAL(textChanged(QString)),
213 job, SLOT(setCommand(QString)) );
214 connect( m_delayH, SIGNAL(valueChanged(int)),
215 SLOT(delayChanged()) );
216 connect( m_delayM, SIGNAL(valueChanged(int)),
217 SLOT(delayChanged()) );
218 connect( m_delay, SIGNAL(valueChanged(int)),
219 SLOT(delayChanged()) );
220 connect( m_loop, SIGNAL(toggled(bool)),
221 job, SLOT(setLoop(bool)) );
222 connect( m_one, SIGNAL(toggled(bool)),
223 job, SLOT(setOneInstance(bool)) );
224 connect( m_stop, SIGNAL(clicked()),
226 connect( m_pause, SIGNAL(clicked()),
227 job, SLOT(pause()) );
228 connect( m_start, SIGNAL(clicked()),
229 job, SLOT(start()) );
230 connect( m_slider, SIGNAL(valueChanged(int)),
231 job, SLOT(setValue(int)) );
233 m_commandLine->lineEdit()->setText( job->command() );
234 m_loop->setChecked( job->loop() );
235 m_one->setChecked( job->oneInstance() );
236 m_counter->display( (int)job->value() );
237 m_slider->setMaximum( job->delay() );
238 m_slider->setValue( job->value() );
241 m_state->setEnabled( false );
242 m_settings->setEnabled( false );
243 m_remove->setEnabled( false );
248 void KTimerPref::jobChanged( KTimerJob *job )
250 KTimerJobItem *item = static_cast<KTimerJobItem*>(job->user());
255 if( item==m_list->currentItem() ) {
258 m_slider->setMaximum( job->delay() );
259 m_slider->setValue( job->value() );
260 m_counter->display( (int)job->value() );
266 void KTimerPref::jobFinished( KTimerJob *job, bool error )
268 KTimerJobItem *item = static_cast<KTimerJobItem*>(job->user());
269 item->setStatus( error );
273 /* Hour/Minute/Second was changed. This slot calculates the seconds until we start
274 the job and inform the current job */
275 void KTimerPref::delayChanged()
277 KTimerJobItem *item = static_cast<KTimerJobItem*>(m_list->currentItem());
279 KTimerJob *job = item->job();
280 int time_sec = job->timeToSeconds( m_delayH->value(), m_delayM->value(), m_delay->value() );
281 job->setDelay( time_sec );
285 // Really quits the application
286 void KTimerPref::exit() {
291 void KTimerPref::done(int result) {
293 QDialog::done(result);
296 void KTimerPref::saveJobs( KConfig *cfg )
298 const int nbList=m_list->topLevelItemCount();
299 for (int num = 0; num < nbList; ++num)
301 KTimerJobItem *item = static_cast<KTimerJobItem*>(m_list->topLevelItem(num));
302 item->job()->save( cfg, QString(QLatin1String( "Job%1" )).arg( num ) );
306 KConfigGroup jobscfg = cfg->group("Jobs");
307 jobscfg.writeEntry( "Number", m_list->topLevelItemCount());
313 void KTimerPref::loadJobs( KConfig *cfg )
315 const int num = cfg->group("Jobs").readEntry( "Number", 0 );
316 for( int n=0; n<num; n++ ) {
317 KTimerJob *job = new KTimerJob;
318 KTimerJobItem *item = new KTimerJobItem( job, m_list );
320 connect( job, SIGNAL(delayChanged(KTimerJob*,uint)),
321 SLOT(jobChanged(KTimerJob*)) );
322 connect( job, SIGNAL(valueChanged(KTimerJob*,uint)),
323 SLOT(jobChanged(KTimerJob*)) );
324 connect( job, SIGNAL(stateChanged(KTimerJob*,States)),
325 SLOT(jobChanged(KTimerJob*)) );
326 connect( job, SIGNAL(commandChanged(KTimerJob*,QString)),
327 SLOT(jobChanged(KTimerJob*)) );
328 connect( job, SIGNAL(finished(KTimerJob*,bool)),
329 SLOT(jobFinished(KTimerJob*,bool)) );
331 job->load( cfg, QString( QLatin1String( "Job%1" ) ).arg(n) );
333 job->setUser( item );
341 /*********************************************************************/
344 struct KTimerJobPrivate {
350 KTimerJob::States state;
351 QList<QProcess *> processes;
358 KTimerJob::KTimerJob( QObject *parent)
361 d = new KTimerJobPrivate;
365 d->oneInstance = true;
370 d->timer = new QTimer( this );
371 connect( d->timer, SIGNAL(timeout()), SLOT(timeout()) );
375 KTimerJob::~KTimerJob()
381 void KTimerJob::save( KConfig *cfg, const QString& grp )
383 KConfigGroup groupcfg = cfg->group(grp);
384 groupcfg.writeEntry( "Delay", d->delay );
385 groupcfg.writePathEntry( "Command", d->command );
386 groupcfg.writeEntry( "Loop", d->loop );
387 groupcfg.writeEntry( "OneInstance", d->oneInstance );
388 groupcfg.writeEntry( "State", (int)d->state );
392 void KTimerJob::load( KConfig *cfg, const QString& grp )
394 KConfigGroup groupcfg = cfg->group(grp);
395 setDelay( groupcfg.readEntry( "Delay", 100 ) );
396 setCommand( groupcfg.readPathEntry( "Command", QString() ) );
397 setLoop( groupcfg.readEntry( "Loop", false ) );
398 setOneInstance( groupcfg.readEntry( "OneInstance", d->oneInstance ) );
399 setState( (States)groupcfg.readEntry( "State", (int)Stopped ) );
403 // Format given seconds to hour:minute:seconds and return QString
404 QString KTimerJob::formatTime( int seconds ) const
407 secondsToHMS( seconds, &h, &m, &s );
408 return QString( QLatin1String( "%1:%2:%3" ) ).arg( h ).arg( m, 2, 10, QLatin1Char( '0' ) ).arg( s,2, 10, QLatin1Char( '0' ) );
412 // calculate seconds from hour, minute and seconds, returns seconds
413 int KTimerJob::timeToSeconds( int hours, int minutes, int seconds ) const
415 return hours * 3600 + minutes * 60 + seconds;
419 // calculates hours, minutes and seconds from given secs.
420 void KTimerJob::secondsToHMS( int secs, int *hours, int *minutes, int *seconds ) const
429 void *KTimerJob::user()
435 void KTimerJob::setUser( void *user )
441 unsigned KTimerJob::delay() const
447 void KTimerJob::pause()
452 void KTimerJob::stop()
457 void KTimerJob::start()
462 void KTimerJob::setDelay( int sec )
464 setDelay( (unsigned)sec );
467 void KTimerJob::setValue( int value )
469 setValue( (unsigned)value );
472 void KTimerJob::setDelay( unsigned sec )
474 if( d->delay!=sec ) {
477 if( d->state==Stopped )
480 emit delayChanged( this, sec );
481 emit changed( this );
486 QString KTimerJob::command() const
492 void KTimerJob::setCommand( const QString &cmd )
494 if( d->command!=cmd ) {
496 emit commandChanged( this, cmd );
497 emit changed( this );
502 bool KTimerJob::loop() const
508 void KTimerJob::setLoop( bool loop )
510 if( d->loop!=loop ) {
512 emit loopChanged( this, loop );
513 emit changed( this );
518 bool KTimerJob::oneInstance() const
520 return d->oneInstance;
524 void KTimerJob::setOneInstance( bool one )
526 if( d->oneInstance!=one ) {
527 d->oneInstance = one;
528 emit oneInstanceChanged( this, one );
529 emit changed( this );
534 unsigned KTimerJob::value() const
540 void KTimerJob::setValue( unsigned value )
542 if( d->value!=value ) {
544 emit valueChanged( this, value );
545 emit changed( this );
550 KTimerJob::States KTimerJob::state() const
556 void KTimerJob::setState( KTimerJob::States state )
558 if( d->state!=state ) {
560 d->timer->start( 1000 );
565 setValue( d->delay );
568 emit stateChanged( this, state );
569 emit changed( this );
574 void KTimerJob::timeout()
576 if( d->state==Started && d->value!=0 ) {
577 setValue( d->value-1 );
581 setValue( d->delay );
589 void KTimerJob::processExited(int, QProcess::ExitStatus status)
591 QProcess * proc = static_cast<QProcess*>(sender());
592 const bool ok = status==0;
593 const int i = d->processes.indexOf( proc);
595 delete d->processes.takeAt(i);
597 if( !ok ) emit error( this );
598 emit finished( this, !ok );
604 void KTimerJob::fire()
606 if( !d->oneInstance || d->processes.isEmpty() ) {
607 QProcess *proc = new QProcess;
608 d->processes.append( proc );
609 connect( proc, SIGNAL(finished(int,QProcess::ExitStatus)),
610 SLOT(processExited(int,QProcess::ExitStatus)) );
611 if (!d->command.simplified ().isEmpty()) {
612 proc->start(d->command);
615 if(proc->state() == QProcess::NotRunning) {
616 const int i = d->processes.indexOf( proc);
618 delete d->processes.takeAt(i);
620 emit finished( this, true );
624 #include "moc_ktimer.cpp"