18c4e2f23a12ef047844c6c0ad0c899a9db634d8
[kitchenalert] / src / kitchenalertmainwindow.cpp
1 /**************************************************************************
2
3         KitchenAlert
4
5         Copyright (C) 2010  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 <QFileDialog>
46 #include <QFile>
47 #include <QIcon>
48
49
50
51 KitchenAlertMainWindow::KitchenAlertMainWindow(QWidget *parent) :
52     QMainWindow(parent),
53     ui(new Ui::KitchenAlertMainWindow)
54     {
55     ui->setupUi(this);
56
57     setWindowIcon(QIcon(":/icon64.png"));
58
59   //load sticky alerts to the model here...
60
61
62
63   //alerts' tableview setup
64
65
66   ui->ComingAlertsTableView->setModel(&model_);
67   ui->ComingAlertsTableView->setSelectionMode(QAbstractItemView::SingleSelection);
68   ui->ComingAlertsTableView->setSelectionBehavior(QAbstractItemView::SelectRows);
69
70
71   //Commented out for testing their potebtial effect for slowdown:
72
73   //  ui->ComingAlertsTableView->horizontalHeader()->setResizeMode(QHeaderView::Fixed);
74 //  ui->ComingAlertsTableView->horizontalHeader()->resizeSection(0,460);
75 //  ui->ComingAlertsTableView->horizontalHeader()->resizeSection(1,140);
76 //  ui->ComingAlertsTableView->horizontalHeader()->resizeSection(2,100);
77
78 //  ui->ComingAlertsTableView->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
79
80
81
82
83 //  ui->ComingAlertsTableView->verticalHeader()->setDefaultSectionSize(40); //Needed with fixed cell height only
84
85
86
87
88   ui->ComingAlertsTableView->horizontalHeader()->hide();
89   ui->ComingAlertsTableView->setWordWrap(true);
90
91
92   //Buttons used when a timer is selected are disabled by default and enabled upon selection
93
94   disableSelectionDependentButtons();
95
96   connect(ui->ComingAlertsTableView->selectionModel(),SIGNAL(selectionChanged(QItemSelection,QItemSelection)),this,SLOT(timerSelected(QItemSelection,QItemSelection)));
97
98   //connect buttons to respective functions
99   connect(ui->CreateNewScheduleButton, SIGNAL (pressed()), this, SLOT (newTimerSequence()));
100   connect(ui->DoneButton,SIGNAL(clicked()),this,SLOT(stop()));
101   connect(ui->RestartButton,SIGNAL(clicked()),this,SLOT(restart()));
102   connect(ui->SnoozeButton,SIGNAL(clicked()),this, SLOT(snooze()));
103   connect(ui->RemoveButton,SIGNAL(clicked()),this,SLOT(remove()));
104   connect(ui->SaveButton,SIGNAL(clicked()),this,SLOT(saveTimer()));
105   connect(ui->loadButton,SIGNAL(clicked()),this,SLOT(loadTimer()));
106
107   // menu setup
108
109   QAction * p_SelectSoundAction = new QAction(tr("Select alert sound"),this);
110   connect(p_SelectSoundAction, SIGNAL(triggered()), this, SLOT(openSelectSoundDialog()));
111   menuBar()->addAction(p_SelectSoundAction);
112
113   QAction * p_AboutAction = new QAction(tr("About"),this);
114   connect(p_AboutAction,SIGNAL(triggered()),this,SLOT(openAbout()));
115   menuBar()->addAction(p_AboutAction);
116     }
117
118 KitchenAlertMainWindow::~KitchenAlertMainWindow()
119 {
120     delete ui;
121 }
122
123 void KitchenAlertMainWindow::changeEvent(QEvent *e)
124 {
125     QMainWindow::changeEvent(e);
126     switch (e->type()) {
127     case QEvent::LanguageChange:
128         ui->retranslateUi(this);
129         break;
130     default:
131         break;
132
133     }
134
135 }
136
137
138 void KitchenAlertMainWindow::newTimerSequence()
139 {
140     CreateTimerSequenceDialog createdialog;
141
142
143     if (createdialog.exec() == QDialog::Accepted) //if user pressed OK
144     {
145
146         //get user input from the dialog
147
148
149        QList<Timer *>  alltimers = createdialog.getTimers();
150
151        // take first timer (currently the only one!)
152
153
154        Timer* timer1 = alltimers.at(0);
155
156
157        //connect alert
158
159
160        connect(timer1,SIGNAL(alert(QModelIndex)),this,SLOT(alert(QModelIndex)));
161
162
163        //Disable buttons, as selection is cleared when view is refreshed to show the new timer
164
165        disableSelectionDependentButtons();
166
167
168        // give timers to the model
169
170        model_.addTimers(alltimers);
171
172
173        //start the timer when it's safely in the model (consider moving this to the model's addTimers function)
174
175
176        timer1->start();
177
178
179     }
180     // if cancelled, do nothing
181
182
183
184 }
185
186
187
188
189
190 void KitchenAlertMainWindow::alert(QModelIndex indexOfAlerter)
191 {
192
193     // The program is brought to front and activated when alerted
194
195     raise();
196     activateWindow();
197
198     // The alerting timer is selected
199     ui->ComingAlertsTableView->selectionModel()->select(QItemSelection(indexOfAlerter,indexOfAlerter),QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows );
200 //    qDebug() << "Should be selected now";
201
202
203     //Snooze button is enabled
204
205
206     ui->SnoozeButton->setEnabled(true);
207
208     //The alert sound is played (consider moving this operation inside timer, as now stopping one alert will silence all alerting alerts)
209
210     alertSound_.play();
211
212 }
213
214
215 void KitchenAlertMainWindow::timerSelected(QItemSelection selected,QItemSelection deselected)
216 {
217     ui->DoneButton->setEnabled(true);
218     ui->RestartButton->setEnabled(true);
219     ui->RemoveButton->setEnabled(true);
220     ui->SaveButton->setEnabled(true);
221
222
223     //enabled only when alerting
224     QModelIndexList indexes = selected.indexes();
225
226     //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
227     QModelIndex index = indexes.value(0);
228     if (index.isValid())
229     {
230         if (model_.isThisTimerAlerting(index) == true)
231         {
232              ui->SnoozeButton->setEnabled(true);
233         }
234         else ui->SnoozeButton->setDisabled(true);
235     }
236
237 }
238
239 void KitchenAlertMainWindow::snooze()
240 {
241     QModelIndex row = selectedRow();
242     if (row.isValid()) //If there was no row selected invalid row was returned
243     {
244         model_.snoozeTimer(row);
245     }
246     ui->SnoozeButton->setDisabled(true);
247     alertSound_.stop();
248
249 }
250
251 void KitchenAlertMainWindow::restart()
252 {
253     QModelIndex row = selectedRow(); //If there was no row selected invalid row was returned
254     if (row.isValid())
255     {
256
257         model_.startTimer(row);
258     }
259     ui->SnoozeButton->setDisabled(true);
260     alertSound_.stop();
261
262 }
263
264 void KitchenAlertMainWindow::stop()
265 {
266     QModelIndex row = selectedRow();
267     if (row.isValid()) //If there was no row selected invalid row was returned
268     {
269         model_.stopTimer(row);
270     }
271     ui->SnoozeButton->setDisabled(true);
272     alertSound_.stop();
273     qDebug() << "Stopped.";
274 }
275
276 QModelIndex KitchenAlertMainWindow::selectedRow()
277 {
278     QModelIndexList chosenRows = ui->ComingAlertsTableView->selectionModel()->selectedRows();
279
280     //The selection mode used allows only one row to be selected at time, so we just take the first
281     //There are indexes for all columns in the row in the list, but as we only use the row, it does not matter which one we take
282
283     return chosenRows.value(0); //gives an invalid QModelIndex if the list is empty
284 }
285
286 void KitchenAlertMainWindow::openSelectSoundDialog()
287 {
288     SelectSoundDialog dialog;
289    if ( dialog.exec() == QDialog::Accepted) //if user pressed OK
290     {
291        if (dialog.isDefaultSoundChecked() == true)
292            alertSound_.setDefaultSound();
293        else
294         alertSound_.setSound(dialog.getSoundFileName());
295
296    //opening a dialog clears the selection so the selection dependen buttons must be disabled
297     }
298     disableSelectionDependentButtons();
299 }
300
301 void KitchenAlertMainWindow::openAbout()
302 {
303     QMessageBox::about(this,tr("About KitchenAlert"),tr("<p>Version %1"
304                                                         "<p>Copyright &copy; Heli Hyv&auml;ttinen 2010"
305                                                          "<p>License: General Public License v3"
306                                                          "<p>Bugtracker and project page: https://garage.maemo.org/projects/kitchenalert/").arg(QApplication::applicationVersion()));
307 }
308
309 bool KitchenAlertMainWindow::event(QEvent *event)
310 {
311     QMainWindow::event(event);
312
313     switch (event->type())
314     {
315         case QEvent::WindowActivate:
316
317             model_.setUpdateViewOnChanges(true);
318               break;
319
320        case QEvent::WindowDeactivate:
321             model_.setUpdateViewOnChanges(false);
322             break;
323
324        default:
325             break;
326     }
327 }
328
329 void KitchenAlertMainWindow::disableSelectionDependentButtons()
330 {
331     ui->DoneButton->setDisabled(true);
332     ui->SnoozeButton->setDisabled(true);
333     ui->RestartButton->setDisabled(true);
334     ui->RemoveButton->setDisabled(true);
335     ui->SaveButton->setDisabled(true);
336 }
337
338 void KitchenAlertMainWindow::remove()
339 {
340    QModelIndex row = selectedRow();
341    if (row.isValid())
342    {
343     model_.removeTimer(row);
344     alertSound_.stop();
345     ui->ComingAlertsTableView->clearSelection();
346     disableSelectionDependentButtons();
347    }
348 }
349
350 void KitchenAlertMainWindow::saveTimer()
351 {
352
353     QModelIndex row = selectedRow();
354
355     if (row.isValid() == false) //If there was no row selected invalid row was returned
356         return;
357
358
359     //file name is asked. As the filename will be appended, there's no point in confirming owerwrite here
360     QString filename = QFileDialog::getSaveFileName(this, "", "", "*.kitchenalert",NULL,QFileDialog::DontConfirmOverwrite);
361
362     disableSelectionDependentButtons();
363
364     qDebug() << filename;
365
366     if (filename.isEmpty()) //user cancelled the dialog (or gave an empty name)
367     {
368         return;
369     }
370
371     if (!filename.endsWith(".kitchenalert"))
372     {
373         filename.append(".kitchenalert");
374
375     }
376
377     qDebug() << "filename appended to " << filename;
378
379
380     //MANUAL CONFIRMATION OF OWERWRITE
381
382     if ( QFile::exists(filename))
383     {
384          //ASK FOR CONFIRMATION
385
386         QString overwriteQuestion ("File ");
387         overwriteQuestion.append(filename);
388         overwriteQuestion.append(" already exists. Do you want to overwrite it?");
389         if (QMessageBox::question(this,"Confirm overwrite?", overwriteQuestion,QMessageBox::Yes | QMessageBox::No,QMessageBox::No) != QMessageBox::Yes)
390         {
391             return;
392         }
393     }
394
395
396
397
398
399     QString errorMessage(tr("Cannot write to file "));
400     errorMessage.append(filename);
401
402     if (!model_.saveTimer(row,filename)) //Save the file, if not successful give an error message
403     {
404         QMessageBox::critical(this,tr("Save timer failed!"), errorMessage);
405     }
406
407
408 }
409
410 void KitchenAlertMainWindow::loadTimer()
411 {
412     QString filename = QFileDialog::getOpenFileName(this,"","",tr("KitchenAlert timer files (*.kitchenalert)"));
413     if (!filename.isEmpty())
414     {
415
416 //        if (!filename.endsWith(".kitchenalert"))      //not needed, the dialog won't let the user to select files not ending with ".kitchenalert"
417 //        {
418 //            filename.append(".kitchenalert");
419 //        }
420
421         QString errorTitle(tr("Failed to load file "));
422         errorTitle.append(filename);
423
424         Timer * p_timer = new Timer();
425         if (!p_timer->load(filename))
426         {
427             QMessageBox::critical(this,errorTitle,tr("Unable to open file or not a valid KitchenAlert timer file."));
428             delete p_timer;
429             return;
430         }
431
432         initializeTimer(p_timer);
433     }
434 }
435
436
437 void KitchenAlertMainWindow::initializeTimer(Timer *p_timer)
438 {
439
440 //connect alert
441
442
443 connect(p_timer,SIGNAL(alert(QModelIndex)),this,SLOT(alert(QModelIndex)));
444
445
446 //Disable buttons, as selection is cleared when view is refreshed to show the new timer
447
448 disableSelectionDependentButtons();
449
450
451 // give timers to the model (model wants list of timers now..)
452
453 QList<Timer *> timerList;
454
455 timerList.append(p_timer);
456 model_.addTimers(timerList);
457
458
459 //start the timer when it's safely in the model (consider moving this to the model's addTimers function)
460
461
462 p_timer->start();
463 }