The state before going to scratchbox
[kitchenalert] / src / kitchenalertmainwindow.cpp
1 /**************************************************************************
2
3         KitchenAlert
4
5         Copyright (C) 2010-2011  Heli Hyvättinen
6
7         This file is part of KitchenAlert.
8
9         Kitchen Alert is free software: you can redistribute it and/or modify
10         it under the terms of the GNU General Public License as published by
11         the Free Software Foundation, either version 3 of the License, or
12         (at your option) any later version.
13
14         This program is distributed in the hope that it will be useful,
15         but WITHOUT ANY WARRANTY; without even the implied warranty of
16         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17         GNU General Public License for more details.
18
19         You should have received a copy of the GNU General Public License
20         along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
22 **************************************************************************/
23
24
25
26
27
28 #include "kitchenalertmainwindow.h"
29 #include "ui_kitchenalertmainwindow.h"
30
31 #include <QString>
32 #include <QList>
33
34
35 #include "createtimersequencedialog.h"
36 #include "selectsounddialog.h"
37
38
39
40 #include <QDebug>
41
42 #include <QAction>
43 #include <QMenuBar>
44 #include <QMessageBox>
45 #include <QSettings>
46 #include <QFileDialog>
47
48   const QString defaultSaveDirectory_ = "/home/user/MyDocs/KitchenAlert/";
49
50
51 KitchenAlertMainWindow::KitchenAlertMainWindow(QWidget *parent) :
52     QMainWindow(parent),
53     ui(new Ui::KitchenAlertMainWindow)
54     {
55
56   ui->setupUi(this);
57
58   setWindowIcon(QIcon(":/kitchenalert.png"));
59
60   //alerts' tableview setup
61
62   ui->ComingAlertsTableView->setModel(&model_);
63   ui->ComingAlertsTableView->setSelectionMode(QAbstractItemView::SingleSelection);
64   ui->ComingAlertsTableView->setSelectionBehavior(QAbstractItemView::SelectRows);
65
66   ui->ComingAlertsTableView->horizontalHeader()->hide();
67 //  ui->ComingAlertsTableView->verticalHeader()->setVisible(true);
68
69   ui->ComingAlertsTableView->horizontalHeader()->setResizeMode(QHeaderView::Fixed);
70   ui->ComingAlertsTableView->horizontalHeader()->resizeSection(0,535);
71   ui->ComingAlertsTableView->horizontalHeader()->resizeSection(1,140);
72   ui->ComingAlertsTableView->horizontalHeader()->resizeSection(2,100);
73
74   ui->ComingAlertsTableView->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
75
76
77   //Buttons used to reacting to an alarm are hidden by default
78
79   disableSelectionDependentButtons();
80
81
82   connect(ui->ComingAlertsTableView->selectionModel(),SIGNAL(selectionChanged(QItemSelection,QItemSelection)),this,SLOT(timerSelected(QItemSelection,QItemSelection)));
83   connect(ui->CreateNewScheduleButton, SIGNAL (clicked()), this, SLOT (newTimerSequence()));
84   connect(ui->DoneButton,SIGNAL(clicked()),this,SLOT(stop()));
85   connect(ui->RestartButton,SIGNAL(clicked()),this,SLOT(restart()));
86   connect(ui->SnoozeButton,SIGNAL(clicked()),this, SLOT(snooze()));
87   connect(ui->RemoveButton,SIGNAL(clicked()),this,SLOT(remove()));
88   connect(ui->SaveButton,SIGNAL(clicked()),this,SLOT(saveTimer()));
89   connect(ui->OpenButton,SIGNAL(clicked()),this,SLOT(loadTimer()));
90
91   // menu setup
92
93   QAction * p_SelectSoundAction = new QAction(tr("Select alert sound"),this);
94   connect(p_SelectSoundAction, SIGNAL(triggered()), this, SLOT(openSelectSoundDialog()));
95   menuBar()->addAction(p_SelectSoundAction);
96
97   QAction * p_AboutAction = new QAction(tr("About"),this);
98   connect(p_AboutAction,SIGNAL(triggered()),this,SLOT(openAbout()));
99   menuBar()->addAction(p_AboutAction);
100     }
101
102 KitchenAlertMainWindow::~KitchenAlertMainWindow()
103 {
104     delete ui;
105 }
106
107 void KitchenAlertMainWindow::changeEvent(QEvent *e)
108 {
109     QMainWindow::changeEvent(e);
110     switch (e->type()) {
111     case QEvent::LanguageChange:
112         ui->retranslateUi(this);
113         break;
114     default:
115         break;
116
117     }
118
119 }
120
121
122 void KitchenAlertMainWindow::newTimerSequence()
123 {
124     CreateTimerSequenceDialog createdialog;
125
126
127     if (createdialog.exec() == QDialog::Accepted) //if user pressed OK
128     {
129
130
131        QList<Timer *>  alltimers = createdialog.getTimers();  //get user input from the dialog
132
133        Timer* timer1 = alltimers.at(0); // take first timer (currently the only one!)
134
135
136
137        connect(timer1,SIGNAL(alert(QModelIndex)),this,SLOT(alert(QModelIndex)));
138
139
140
141        connect(this,SIGNAL(defaultSoundEnabled()),timer1,SLOT(enableDefaultSound()));
142        connect(this,SIGNAL(soundChanged(QString)),timer1,SLOT(changeAlertSound(QString)));
143
144
145
146         model_.addTimers(alltimers); // give timers to the model, they are started automatically by default
147
148  //       ui->ComingAlertsTableView->resizeColumnsToContents();
149
150
151         //Disable buttons, as selection is cleared when view is refreshed to show the new timer
152         //But only if the timer has not already alerted and thus been selected
153
154         if (!selectedRow().isValid())
155             disableSelectionDependentButtons();
156
157
158
159     }
160     // if cancelled, do nothing
161
162
163
164 }
165
166
167
168
169
170 void KitchenAlertMainWindow::alert(QModelIndex indexOfAlerter)
171 {
172
173     // The program is brought to front and activated when alerted
174
175
176     activateWindow();
177
178 // removing everything below does not solve the bug #6752!
179
180     raise();  //this may be unnecessary
181
182     // The alerting timer is selected
183     ui->ComingAlertsTableView->selectionModel()->select(QItemSelection(indexOfAlerter,indexOfAlerter),QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows );
184
185     //Scrolls the view so that the alerting timer is visible
186     ui->ComingAlertsTableView->scrollTo(indexOfAlerter);
187
188    // qDebug() << "Should be selected now";
189
190
191     //Snooze button is enabled
192
193
194     ui->SnoozeButton->setEnabled(true);
195 //qDebug ("Snooze on when alerting");
196
197 }
198
199
200 void KitchenAlertMainWindow::timerSelected(QItemSelection selected,QItemSelection)
201 {
202     ui->DoneButton->setEnabled(true);
203     ui->RestartButton->setEnabled(true);
204     ui->RemoveButton->setEnabled(true);
205     ui->SaveButton->setEnabled(true);
206
207
208     //snooze button enabled only when alerting
209     QModelIndexList indexes = selected.indexes();
210
211     //the selection model only allows selecting one row at the time & we only need to know the row, so we can just take the first one
212     QModelIndex index = indexes.value(0);
213     if (index.isValid())
214     {
215         if (model_.isThisTimerAlerting(index) == true)
216         {
217              ui->SnoozeButton->setEnabled(true);
218 //qDebug() << "Snooze on";
219         }
220         else
221         {
222             ui->SnoozeButton->setDisabled(true);
223 //qDebug() << "Snooze off";
224         }
225     }
226
227 }
228
229 void KitchenAlertMainWindow::snooze()
230 {
231     QModelIndex row = selectedRow();
232     if (row.isValid()) //If there was no row selected invalid row was returned
233     {
234         model_.snoozeTimer(row);
235     }
236     ui->SnoozeButton->setDisabled(true);
237
238
239 }
240
241 void KitchenAlertMainWindow::restart()
242 {
243     QModelIndex row = selectedRow(); //If there was no row selected invalid row was returned
244     if (row.isValid())
245     {
246
247         model_.startTimer(row);
248     }
249
250
251    if (model_.isThisTimerAlerting(row) == false) //This has to be checked, because 00:00:00 alerts alert *before* the program execution reaches here
252     {
253         ui->SnoozeButton->setDisabled(true);
254     }
255  //   qDebug () << "disabled snooze because of restart";
256
257
258 }
259
260 void KitchenAlertMainWindow::stop()
261 {
262     QModelIndex row = selectedRow();
263     if (row.isValid()) //If there was no row selected invalid row was returned
264     {
265         model_.stopTimer(row);
266     }
267     ui->SnoozeButton->setDisabled(true);
268
269 }
270
271 QModelIndex KitchenAlertMainWindow::selectedRow()
272 {
273     //Returns the cells in row 0 that have the whole row selected (the selection mode used allows only selecting whole rows
274
275     QModelIndexList chosenRows = ui->ComingAlertsTableView->selectionModel()->selectedRows();
276
277     //The selection mode used allows only one row to be selected at time, so we just take the first
278
279
280     return chosenRows.value(0); //gives an invalid QModelIndex if the list is empty
281 }
282
283 void KitchenAlertMainWindow::openSelectSoundDialog()
284 {
285
286     SelectSoundDialog dialog;
287    if ( dialog.exec() == QDialog::Accepted) //if user pressed OK
288     {
289        QSettings settings ("KitchenAlert","KitchenAlert");
290       
291        if (dialog.isDefaultSoundChecked() == true)
292        { 
293          
294            settings.setValue("UseDefaultSound",true); 
295            emit defaultSoundEnabled();
296        }   
297       else
298        {
299            QString filename = dialog.getSoundFileName();
300            settings.setValue("UseDefaultSound",false);
301            settings.setValue("soundfile",filename);
302            emit soundChanged(filename);
303        }
304
305     }
306
307 }
308
309 void KitchenAlertMainWindow::openAbout()
310 {
311     QMessageBox::about(this,tr("About KitchenAlert"),tr("<p>Version %1"
312                                                         "<p>Copyright &copy; Heli Hyv&auml;ttinen 2010-2011"
313                                                          "<p>License: General Public License v3"
314                                                          "<p>Web page: http://kitchenalert.garage.maemo.org/"
315                                                          "<p>Bugtracker: https://garage.maemo.org/projects/kitchenalert/").arg(QApplication::applicationVersion()));
316 }
317
318 bool KitchenAlertMainWindow::event(QEvent *event)
319 {
320
321
322     switch (event->type())
323     {
324         case QEvent::WindowActivate:
325
326             model_.setUpdateViewOnChanges(true);
327 //            ui->debugLabel->setText("Returned to the application!");
328             break;
329
330        case QEvent::WindowDeactivate:
331             model_.setUpdateViewOnChanges(false);
332 //            ui->debugLabel->setText("");
333             break;
334
335        default:
336             break;
337
338     }
339
340     return QMainWindow::event(event); // Send the event to the base class implementation (also when handling the event in this function): necessary for the program to work!
341 }
342
343 void KitchenAlertMainWindow::disableSelectionDependentButtons()
344 {
345     ui->DoneButton->setDisabled(true);
346     ui->SnoozeButton->setDisabled(true);
347     ui->RestartButton->setDisabled(true);
348     ui->RemoveButton->setDisabled(true);
349     ui->SaveButton->setDisabled(true);
350
351
352 }
353
354 void KitchenAlertMainWindow::initializeAlertSound()
355 {
356     QSettings settings;
357
358     bool useDefaultSound = settings.value("UseDefaultSound",true).toBool();
359     QString filename = settings.value("soundfile","").toString();
360
361     if (useDefaultSound == true)
362     {
363         openSelectSoundDialog();
364     }
365     else if (filename.isEmpty())
366     {
367         openSelectSoundDialog();
368     }
369
370    QString currentFilename = settings.value("soundfile","").toString();
371
372    if (currentFilename.isEmpty())
373    {
374         ui->debugLabel->setText("<FONT color=red>No alert sound file set. Alert sound will not be played!</FONT>");
375
376    }
377
378 }
379
380 void KitchenAlertMainWindow::remove()
381 {
382     QModelIndex row = selectedRow();
383     if (row.isValid()) //If there was no row selected invalid row was returned
384     {
385         QString text = tr("Are you sure you want to remove this timer from the list:\n");
386         text.append((row.data().toString()));
387         if (QMessageBox::question(this,tr("Confirm timer removal"),text,QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes)
388         {
389             model_.removeTimer(row);
390             ui->ComingAlertsTableView->clearSelection();
391             disableSelectionDependentButtons();
392
393         }
394     }
395
396 }
397
398 void KitchenAlertMainWindow::saveTimer()
399 {
400
401     QModelIndex row = selectedRow();
402
403     if (row.isValid() == false) //If there was no row selected invalid row was returned
404         return;
405
406
407     //file name is asked. As the filename will be appended, there's no point in confirming owerwrite here
408     QString filename = QFileDialog::getSaveFileName(this, "", defaultSaveDirectory_, "*.kitchenalert",NULL,QFileDialog::DontConfirmOverwrite);
409
410
411
412 //    qDebug() << filename;
413
414     if (filename.isEmpty()) //user cancelled the dialog (or gave an empty name)
415     {
416         return;
417     }
418
419     if (!filename.endsWith(".kitchenalert"))
420     {
421         filename.append(".kitchenalert");
422
423     }
424
425   //  qDebug() << "filename appended to " << filename;
426
427
428     //MANUAL CONFIRMATION OF OWERWRITE
429
430     if ( QFile::exists(filename))
431     {
432          //ASK FOR CONFIRMATION
433
434         QString overwriteQuestion ("File ");
435         overwriteQuestion.append(filename);
436         overwriteQuestion.append(" already exists. Do you want to overwrite it?");
437         if (QMessageBox::question(this,"Confirm overwrite?", overwriteQuestion,QMessageBox::Yes | QMessageBox::No,QMessageBox::No) != QMessageBox::Yes)
438         {
439             return;
440         }
441     }
442
443
444
445
446     QString errorMessage(tr("Cannot write to file "));
447     errorMessage.append(filename);
448
449     if (!model_.saveTimer(row,filename)) //Save the file, if not successful give an error message
450     {
451         QMessageBox::critical(this,tr("Save timer failed!"), errorMessage);
452     }
453
454
455 }
456
457 void KitchenAlertMainWindow::loadTimer()
458 {
459     QString filename = QFileDialog::getOpenFileName(this,"",defaultSaveDirectory_,tr("KitchenAlert timer files (*.kitchenalert)"));
460     if (!filename.isEmpty())
461     {
462
463 //        if (!filename.endsWith(".kitchenalert"))      //not needed, the dialog won't let the user to select files not ending with ".kitchenalert"
464 //        {
465 //            filename.append(".kitchenalert");
466 //        }
467
468         QString errorTitle(tr("Failed to load file "));
469         errorTitle.append(filename);
470
471         Timer * p_timer = new Timer();
472         if (!p_timer->load(filename))
473         {
474             QMessageBox::critical(this,errorTitle,tr("Unable to open file or not a valid KitchenAlert timer file."));
475             delete p_timer;
476             return;
477         }
478
479         initializeTimer(p_timer);
480     }
481 }
482
483 void KitchenAlertMainWindow::initializeTimer(Timer *p_timer)
484 {
485
486 //connect alert
487
488
489 connect(p_timer,SIGNAL(alert(QModelIndex)),this,SLOT(alert(QModelIndex)));
490
491
492 //connect change sound functions
493
494 connect(this,SIGNAL(defaultSoundEnabled()),p_timer,SLOT(enableDefaultSound()));
495 connect(this,SIGNAL(soundChanged(QString)),p_timer,SLOT(changeAlertSound(QString)));
496
497
498 //Disable buttons, as selection is cleared when view is refreshed to show the new timer
499
500 disableSelectionDependentButtons();
501
502
503 // give timers to the model (model wants list of timers now..)
504
505 QList<Timer *> timerList;
506
507 timerList.append(p_timer);
508 model_.addTimers(timerList,true); //timer gets started in the model
509
510 }
511
512
513