OSDN Git Service

gwenview: fix rotated test for the case of dsd_1838.nef
[kde/kde-extraapps.git] / ktimer / ktimer.cpp
1 /*
2  * Copyright 2001 Stefan Schimanski <1Stein@gmx.de>
3  *
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.
8  *
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.
13  *
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.
17  */
18
19 #include "ktimer.h"
20
21 #include <QProcess>
22 #include <QTimer>
23
24 #include <klineedit.h>
25 #include <kiconloader.h>
26 #include <kapplication.h>
27 #include <kfiledialog.h>
28 #include <kglobal.h>
29 #include <ktoolinvocation.h>
30 #include <kstandardguiitem.h>
31 #include <kaction.h>
32 #include <kstandardaction.h>
33 #include "kstatusnotifieritem.h"
34
35 class KTimerJobItem : public QTreeWidgetItem {
36 public:
37     KTimerJobItem( KTimerJob *job, QTreeWidget *parent )
38         : QTreeWidgetItem() {
39                         parent->addTopLevelItem(this);
40         m_job = job;
41         m_error = false;
42         update();
43     }
44
45     KTimerJobItem( KTimerJob *job, QTreeWidget * parent, QTreeWidgetItem *after )
46         : QTreeWidgetItem() {
47                         int otherItemIndex = parent->indexOfTopLevelItem(after);
48                         parent->insertTopLevelItem(otherItemIndex + 1, this);
49         m_job = job;
50         m_error = false;
51         update();
52     }
53
54     virtual ~KTimerJobItem() {
55         delete m_job;
56     }
57
58     KTimerJob *job() { return m_job; }
59
60     void setStatus( bool error ) {
61         m_error = error;
62         update();
63     }
64
65     void update() {
66         setText( 0, m_job->formatTime(m_job->value()) );
67
68         if( m_error )
69             setIcon( 0, KIcon( QLatin1String( "process-stop" )) );
70         else
71             setIcon( 0, QPixmap() );
72
73         setText( 1, m_job->formatTime(m_job->delay()) );
74
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;
79         }
80
81         setText( 3, m_job->command() );
82     }
83
84 private:
85     bool m_error;
86     KTimerJob *m_job;
87 };
88
89
90 /***************************************************************/
91
92
93 struct KTimerPrefPrivate
94 {
95     QList<KTimerJob *> jobs;
96 };
97
98 KTimerPref::KTimerPref( QWidget *parent)
99     : QDialog( parent )
100 {
101     d = new KTimerPrefPrivate;
102
103     setupUi(this);
104
105     // set icons
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" )) );
109
110     // create tray icon
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());
117
118     // Exit
119     KAction *exit = KStandardAction::quit(this, SLOT(exit()), this);
120     addAction(exit);
121
122     // connect
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() );
129
130     show();
131 }
132
133
134 KTimerPref::~KTimerPref()
135 {
136     delete d;
137 }
138
139 void KTimerPref::saveAllJobs() {
140     saveJobs( KGlobal::config().data() );
141 }
142
143
144 void KTimerPref::add()
145 {
146     KTimerJob *job = new KTimerJob;
147     KTimerJobItem *item = new KTimerJobItem( job, m_list );
148
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)) );
159
160     job->setUser( item );
161
162     // Qt drops currentChanged signals on first item (bug?)
163     if( m_list->topLevelItemCount()==1 )
164       currentChanged( item , NULL);
165
166     m_list->setCurrentItem( item );
167     m_list->update();
168 }
169
170
171 void KTimerPref::remove()
172 {
173     delete m_list->currentItem();
174     m_list->update();
175 }
176
177 void KTimerPref::help()
178 {
179     KToolInvocation::invokeHelp();
180 }
181
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 */)
184 {
185     KTimerJobItem *item = static_cast<KTimerJobItem*>(i);
186     if( item ) {
187         KTimerJob *job = item->job();
188
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();
196         m_one->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();
204
205         // Set hour, minute and second QSpinBoxes before we connect to signals.
206         int h, m, s;
207         job->secondsToHMS( job->delay(), &h, &m, &s );
208         m_delayH->setValue( h );
209         m_delayM->setValue( m );
210         m_delay->setValue( s );
211
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()),
225                  job, SLOT(stop()) );
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)) );
232
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() );
239
240     } else {
241         m_state->setEnabled( false );
242         m_settings->setEnabled( false );
243         m_remove->setEnabled( false );
244     }
245 }
246
247
248 void KTimerPref::jobChanged( KTimerJob *job )
249 {
250     KTimerJobItem *item = static_cast<KTimerJobItem*>(job->user());
251     if( item ) {
252         item->update();
253         m_list->update();
254
255         if( item==m_list->currentItem() ) {
256
257             // XXX optimize
258             m_slider->setMaximum( job->delay() );
259             m_slider->setValue( job->value() );
260             m_counter->display( (int)job->value() );
261         }
262     }
263 }
264
265
266 void KTimerPref::jobFinished( KTimerJob *job, bool error )
267 {
268     KTimerJobItem *item = static_cast<KTimerJobItem*>(job->user());
269     item->setStatus( error );
270     m_list->update();
271 }
272
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()
276 {
277     KTimerJobItem *item = static_cast<KTimerJobItem*>(m_list->currentItem());
278     if ( item ) {
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 );
282     }
283 }
284
285 // Really quits the application
286 void KTimerPref::exit() {
287     done(0);
288     qApp->quit();
289 }
290
291 void KTimerPref::done(int result) {
292     saveAllJobs();
293     QDialog::done(result);
294 }
295
296 void KTimerPref::saveJobs( KConfig *cfg )
297 {
298         const int nbList=m_list->topLevelItemCount();
299         for (int num = 0; num < nbList; ++num)
300         {
301                 KTimerJobItem *item = static_cast<KTimerJobItem*>(m_list->topLevelItem(num));
302         item->job()->save( cfg, QString(QLatin1String( "Job%1" )).arg( num ) );
303
304         }
305
306         KConfigGroup jobscfg = cfg->group("Jobs");
307     jobscfg.writeEntry( "Number", m_list->topLevelItemCount());
308
309     jobscfg.sync();
310 }
311
312
313 void KTimerPref::loadJobs( KConfig *cfg )
314 {
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 );
319
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)) );
330
331             job->load( cfg, QString( QLatin1String( "Job%1" ) ).arg(n) );
332
333             job->setUser( item );
334             jobChanged ( job);
335     }
336
337     m_list->update();
338 }
339
340
341 /*********************************************************************/
342
343
344 struct KTimerJobPrivate {
345     unsigned delay;
346     QString command;
347     bool loop;
348     bool oneInstance;
349     unsigned value;
350     KTimerJob::States state;
351     QList<QProcess *> processes;
352     void *user;
353
354     QTimer *timer;
355 };
356
357
358 KTimerJob::KTimerJob( QObject *parent)
359     : QObject( parent )
360 {
361     d = new KTimerJobPrivate;
362
363     d->delay = 100;
364     d->loop = false;
365     d->oneInstance = true;
366     d->value = 100;
367     d->state = Stopped;
368     d->user = 0;
369
370     d->timer = new QTimer( this );
371     connect( d->timer, SIGNAL(timeout()), SLOT(timeout()) );
372 }
373
374
375 KTimerJob::~KTimerJob()
376 {
377     delete d;
378 }
379
380
381 void KTimerJob::save( KConfig *cfg, const QString& grp )
382 {
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 );
389 }
390
391
392 void KTimerJob::load( KConfig *cfg, const QString& grp )
393 {
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 ) );
400 }
401
402
403 // Format given seconds to hour:minute:seconds and return QString
404 QString KTimerJob::formatTime( int seconds ) const
405 {
406     int h, m, s;
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' ) );
409 }
410
411
412 // calculate seconds from hour, minute and seconds, returns seconds
413 int KTimerJob::timeToSeconds( int hours, int minutes, int seconds ) const
414 {
415     return hours * 3600 + minutes * 60 + seconds;
416 }
417
418
419 // calculates hours, minutes and seconds from given secs.
420 void KTimerJob::secondsToHMS( int secs, int *hours, int *minutes, int *seconds ) const
421 {
422     int s = secs;
423     (*hours) = s / 3600;
424     s = s % 3600;
425     (*minutes) = s / 60;
426     (*seconds) = s % 60;
427 }
428
429 void *KTimerJob::user()
430 {
431     return d->user;
432 }
433
434
435 void KTimerJob::setUser( void *user )
436 {
437     d->user = user;
438 }
439
440
441 unsigned KTimerJob::delay() const
442 {
443     return d->delay;
444 }
445
446
447 void KTimerJob::pause()
448 {
449     setState( Paused );
450 }
451
452 void KTimerJob::stop()
453 {
454     setState( Stopped );
455 }
456
457 void KTimerJob::start()
458 {
459     setState( Started );
460 }
461
462 void KTimerJob::setDelay( int sec )
463 {
464     setDelay( (unsigned)sec );
465 }
466
467 void KTimerJob::setValue( int value )
468 {
469     setValue( (unsigned)value );
470 }
471
472 void KTimerJob::setDelay( unsigned sec )
473 {
474     if( d->delay!=sec ) {
475         d->delay = sec;
476
477         if( d->state==Stopped )
478             setValue( sec );
479
480         emit delayChanged( this, sec );
481         emit changed( this );
482     }
483 }
484
485
486 QString KTimerJob::command() const
487 {
488     return d->command;
489 }
490
491
492 void KTimerJob::setCommand( const QString &cmd )
493 {
494     if( d->command!=cmd ) {
495         d->command = cmd;
496         emit commandChanged( this, cmd );
497         emit changed( this );
498     }
499 }
500
501
502 bool KTimerJob::loop() const
503 {
504     return d->loop;
505 }
506
507
508 void KTimerJob::setLoop( bool loop )
509 {
510     if( d->loop!=loop ) {
511         d->loop = loop;
512         emit loopChanged( this, loop );
513         emit changed( this );
514     }
515 }
516
517
518 bool KTimerJob::oneInstance() const
519 {
520     return d->oneInstance;
521 }
522
523
524 void KTimerJob::setOneInstance( bool one )
525 {
526     if( d->oneInstance!=one ) {
527         d->oneInstance = one;
528         emit oneInstanceChanged( this, one );
529         emit changed( this );
530     }
531 }
532
533
534 unsigned KTimerJob::value() const
535 {
536     return d->value;
537 }
538
539
540 void KTimerJob::setValue( unsigned value )
541 {
542     if( d->value!=value ) {
543         d->value = value;
544         emit valueChanged( this, value );
545         emit changed( this );
546     }
547 }
548
549
550 KTimerJob::States KTimerJob::state() const
551 {
552     return d->state;
553 }
554
555
556 void KTimerJob::setState( KTimerJob::States state )
557 {
558     if( d->state!=state ) {
559         if( state==Started )
560             d->timer->start( 1000 );
561         else
562             d->timer->stop();
563
564         if( state==Stopped )
565             setValue( d->delay );
566
567         d->state = state;
568         emit stateChanged( this, state );
569         emit changed( this );
570     }
571 }
572
573
574 void KTimerJob::timeout()
575 {
576     if( d->state==Started && d->value!=0 ) {
577         setValue( d->value-1 );
578         if( d->value==0 ) {
579             fire();
580             if( d->loop )
581                 setValue( d->delay );
582             else
583                 stop();
584         }
585     }
586 }
587
588
589 void KTimerJob::processExited(int, QProcess::ExitStatus status)
590 {
591         QProcess * proc = static_cast<QProcess*>(sender());
592     const bool ok = status==0;
593     const int i = d->processes.indexOf( proc);
594     if (i != -1)
595         delete d->processes.takeAt(i);
596
597     if( !ok ) emit error( this );
598     emit finished( this, !ok );
599 }
600
601
602
603
604 void KTimerJob::fire()
605 {
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);
613                 emit fired( this );
614         }
615         if(proc->state() == QProcess::NotRunning) {
616             const int i = d->processes.indexOf( proc);
617             if (i != -1)
618                 delete d->processes.takeAt(i);
619             emit error( this );
620             emit finished( this, true );
621         }
622     }
623 }
624 #include "moc_ktimer.cpp"