1 /**************************************************************************
5 Copyright (C) 2010-2011 Heli Hyvättinen
7 This file is part of KitchenAlert.
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.
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.
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/>.
22 **************************************************************************/
28 #include "kitchenalertmainwindow.h"
29 #include "ui_kitchenalertmainwindow.h"
35 #include "createtimersequencedialog.h"
36 #include "selectsounddialog.h"
42 #include <QMessageBox>
44 #include <QFileDialog>
46 #include <QStringListModel>
48 #include "stickydialog.h"
51 KitchenAlertMainWindow::KitchenAlertMainWindow(QWidget *parent) :
53 ui(new Ui::KitchenAlertMainWindow)
56 defaultSaveDirectory_ = "/home/user/KitchenAlert";
60 setWindowIcon(QIcon(":/kitchenalert.png"));
62 //alerts' tableview setup
64 ui->ComingAlertsTableView->setModel(&model_);
65 ui->ComingAlertsTableView->setSelectionMode(QAbstractItemView::SingleSelection);
66 ui->ComingAlertsTableView->setSelectionBehavior(QAbstractItemView::SelectRows);
68 ui->ComingAlertsTableView->horizontalHeader()->hide();
69 // ui->ComingAlertsTableView->verticalHeader()->setVisible(true);
71 ui->ComingAlertsTableView->horizontalHeader()->setResizeMode(QHeaderView::Fixed);
72 ui->ComingAlertsTableView->horizontalHeader()->resizeSection(0,535);
73 ui->ComingAlertsTableView->horizontalHeader()->resizeSection(1,140);
74 ui->ComingAlertsTableView->horizontalHeader()->resizeSection(2,100);
76 ui->ComingAlertsTableView->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
79 //Buttons used to reacting to an alarm are hidden by default
81 disableSelectionDependentButtons();
84 connect(ui->ComingAlertsTableView->selectionModel(),SIGNAL(selectionChanged(QItemSelection,QItemSelection)),this,SLOT(timerSelected(QItemSelection,QItemSelection)));
85 connect(ui->CreateNewScheduleButton, SIGNAL (clicked()), this, SLOT (newTimerSequence()));
86 connect(ui->DoneButton,SIGNAL(clicked()),this,SLOT(stop()));
87 connect(ui->RestartButton,SIGNAL(clicked()),this,SLOT(restart()));
88 connect(ui->SnoozeButton,SIGNAL(clicked()),this, SLOT(snooze()));
89 connect(ui->RemoveButton,SIGNAL(clicked()),this,SLOT(remove()));
90 connect(ui->SaveButton,SIGNAL(clicked()),this,SLOT(saveTimer()));
91 connect(ui->OpenButton,SIGNAL(clicked()),this,SLOT(loadTimer()));
95 QAction * p_SelectSoundAction = new QAction(tr("Select alert sound"),this);
96 connect(p_SelectSoundAction, SIGNAL(triggered()), this, SLOT(openSelectSoundDialog()));
97 menuBar()->addAction(p_SelectSoundAction);
99 QAction * p_AboutAction = new QAction(tr("About"),this);
100 connect(p_AboutAction,SIGNAL(triggered()),this,SLOT(openAbout()));
101 menuBar()->addAction(p_AboutAction);
103 QAction * p_StickyAction = new QAction(tr("Edit sticky timers"),this);
104 connect(p_StickyAction, SIGNAL(triggered()),this,SLOT(openStickyDialog()));
105 menuBar()->addAction(p_StickyAction);
107 QTimer::singleShot(0,this,SLOT(loadStickies())); //Load sticky timers after construction to speed the application showing up
111 KitchenAlertMainWindow::~KitchenAlertMainWindow()
116 void KitchenAlertMainWindow::changeEvent(QEvent *e)
118 QMainWindow::changeEvent(e);
120 case QEvent::LanguageChange:
121 ui->retranslateUi(this);
131 void KitchenAlertMainWindow::newTimerSequence()
133 CreateTimerSequenceDialog createdialog;
136 if (createdialog.exec() == QDialog::Accepted) //if user pressed OK
140 QList<Timer *> alltimers = createdialog.getTimers(); //get user input from the dialog
142 Timer* timer1 = alltimers.at(0); // take first timer (currently the only one!)
146 connect(timer1,SIGNAL(alert(QModelIndex)),this,SLOT(alert(QModelIndex)));
150 connect(this,SIGNAL(defaultSoundEnabled()),timer1,SLOT(enableDefaultSound()));
151 connect(this,SIGNAL(soundChanged(QString)),timer1,SLOT(changeAlertSound(QString)));
155 model_.addTimers(alltimers); // give timers to the model, they are started automatically by default
157 // ui->ComingAlertsTableView->resizeColumnsToContents();
160 //Disable buttons, as selection is cleared when view is refreshed to show the new timer
161 //But only if the timer has not already alerted and thus been selected
163 if (!selectedRow().isValid())
164 disableSelectionDependentButtons();
169 // if cancelled, do nothing
179 void KitchenAlertMainWindow::alert(QModelIndex indexOfAlerter)
182 // The program is brought to front and activated when alerted
187 // removing everything below does not solve the bug #6752!
189 raise(); //this may be unnecessary
191 // The alerting timer is selected
192 ui->ComingAlertsTableView->selectionModel()->select(QItemSelection(indexOfAlerter,indexOfAlerter),QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows );
194 //Scrolls the view so that the alerting timer is visible
195 ui->ComingAlertsTableView->scrollTo(indexOfAlerter);
197 // qDebug() << "Should be selected now";
200 //Snooze button is enabled
203 ui->SnoozeButton->setEnabled(true);
204 //qDebug ("Snooze on when alerting");
209 void KitchenAlertMainWindow::timerSelected(QItemSelection selected,QItemSelection)
211 ui->DoneButton->setEnabled(true);
212 ui->RestartButton->setEnabled(true);
213 ui->RemoveButton->setEnabled(true);
214 ui->SaveButton->setEnabled(true);
217 //snooze button enabled only when alerting
218 QModelIndexList indexes = selected.indexes();
220 //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
221 QModelIndex index = indexes.value(0);
224 if (model_.isThisTimerAlerting(index) == true)
226 ui->SnoozeButton->setEnabled(true);
227 //qDebug() << "Snooze on";
231 ui->SnoozeButton->setDisabled(true);
232 //qDebug() << "Snooze off";
238 void KitchenAlertMainWindow::snooze()
240 QModelIndex row = selectedRow();
241 if (row.isValid()) //If there was no row selected invalid row was returned
243 model_.snoozeTimer(row);
245 ui->SnoozeButton->setDisabled(true);
250 void KitchenAlertMainWindow::restart()
252 QModelIndex row = selectedRow(); //If there was no row selected invalid row was returned
256 model_.startTimer(row);
260 if (model_.isThisTimerAlerting(row) == false) //This has to be checked, because 00:00:00 alerts alert *before* the program execution reaches here
262 ui->SnoozeButton->setDisabled(true);
264 // qDebug () << "disabled snooze because of restart";
269 void KitchenAlertMainWindow::stop()
271 QModelIndex row = selectedRow();
272 if (row.isValid()) //If there was no row selected invalid row was returned
274 model_.stopTimer(row);
276 ui->SnoozeButton->setDisabled(true);
280 QModelIndex KitchenAlertMainWindow::selectedRow()
282 //Returns the cells in row 0 that have the whole row selected (the selection mode used allows only selecting whole rows
284 QModelIndexList chosenRows = ui->ComingAlertsTableView->selectionModel()->selectedRows();
286 //The selection mode used allows only one row to be selected at time, so we just take the first
289 return chosenRows.value(0); //gives an invalid QModelIndex if the list is empty
292 void KitchenAlertMainWindow::openSelectSoundDialog()
295 SelectSoundDialog dialog;
296 if ( dialog.exec() == QDialog::Accepted) //if user pressed OK
298 QSettings settings ("KitchenAlert","KitchenAlert");
300 if (dialog.isDefaultSoundChecked() == true)
303 settings.setValue("UseDefaultSound",true);
304 emit defaultSoundEnabled();
308 QString filename = dialog.getSoundFileName();
309 settings.setValue("UseDefaultSound",false);
310 settings.setValue("soundfile",filename);
311 emit soundChanged(filename);
318 void KitchenAlertMainWindow::openAbout()
320 QMessageBox::about(this,tr("About KitchenAlert"),tr("<p>Version %1"
321 "<p>Copyright © Heli Hyvättinen 2010-2011"
322 "<p>License: General Public License v3"
323 "<p>Web page: http://kitchenalert.garage.maemo.org/"
324 "<p>Bugtracker: https://garage.maemo.org/projects/kitchenalert/").arg(QApplication::applicationVersion()));
327 bool KitchenAlertMainWindow::event(QEvent *event)
331 switch (event->type())
333 case QEvent::WindowActivate:
335 model_.setUpdateViewOnChanges(true);
336 // ui->debugLabel->setText("Returned to the application!");
339 case QEvent::WindowDeactivate:
340 model_.setUpdateViewOnChanges(false);
341 // ui->debugLabel->setText("");
349 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!
352 void KitchenAlertMainWindow::disableSelectionDependentButtons()
354 ui->DoneButton->setDisabled(true);
355 ui->SnoozeButton->setDisabled(true);
356 ui->RestartButton->setDisabled(true);
357 ui->RemoveButton->setDisabled(true);
358 ui->SaveButton->setDisabled(true);
363 void KitchenAlertMainWindow::initializeAlertSound()
367 bool useDefaultSound = settings.value("UseDefaultSound",true).toBool();
368 QString filename = settings.value("soundfile","").toString();
370 if (useDefaultSound == true)
372 openSelectSoundDialog();
374 else if (filename.isEmpty())
376 openSelectSoundDialog();
379 QString currentFilename = settings.value("soundfile","").toString();
381 if (currentFilename.isEmpty())
383 ui->debugLabel->setText("<FONT color=red>No alert sound file set. Alert sound will not be played!</FONT>");
389 void KitchenAlertMainWindow::remove()
391 QModelIndex row = selectedRow();
392 if (row.isValid()) //If there was no row selected invalid row was returned
394 QString text = tr("Are you sure you want to remove this timer from the list:\n");
395 text.append((row.data().toString()));
396 if (QMessageBox::question(this,tr("Confirm timer removal"),text,QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes)
398 model_.removeTimer(row);
399 ui->ComingAlertsTableView->clearSelection();
400 disableSelectionDependentButtons();
407 void KitchenAlertMainWindow::saveTimer()
410 QModelIndex row = selectedRow();
412 if (row.isValid() == false) //If there was no row selected invalid row was returned
416 //file name is asked. As the filename will be appended, there's no point in confirming owerwrite here
417 QString filename = QFileDialog::getSaveFileName(this, "", defaultSaveDirectory_, "*.kitchenalert",NULL,QFileDialog::DontConfirmOverwrite);
421 // qDebug() << filename;
423 if (filename.isEmpty()) //user cancelled the dialog (or gave an empty name)
428 if (!filename.endsWith(".kitchenalert"))
430 filename.append(".kitchenalert");
434 // qDebug() << "filename appended to " << filename;
437 //MANUAL CONFIRMATION OF OWERWRITE
439 if ( QFile::exists(filename))
441 //ASK FOR CONFIRMATION
443 QString overwriteQuestion ("File ");
444 overwriteQuestion.append(filename);
445 overwriteQuestion.append(" already exists. Do you want to overwrite it?");
446 if (QMessageBox::question(this,"Confirm overwrite?", overwriteQuestion,QMessageBox::Yes | QMessageBox::No,QMessageBox::No) != QMessageBox::Yes)
455 QString errorMessage(tr("Cannot write to file "));
456 errorMessage.append(filename);
458 if (!model_.saveTimer(row,filename)) //Save the file, if not successful give an error message
460 QMessageBox::critical(this,tr("Save timer failed!"), errorMessage);
466 void KitchenAlertMainWindow::loadTimer()
469 // If the default save directory does not exist use /home/user instead (as that's what the save dialog will use)
470 // This avoids a situation where save directs to a folder that cannot be accessed with open...
472 QString startDirectory;
474 if (QFile(defaultSaveDirectory_).exists())
476 startDirectory = defaultSaveDirectory_;
480 startDirectory = "/home/user/";
481 qDebug () << "default save directory not found";
485 //Get the filename to open with a dialog
487 QString filename = QFileDialog::getOpenFileName(this,"",startDirectory,tr("KitchenAlert timer files (*.kitchenalert)"));
488 if (!filename.isEmpty())
491 // if (!filename.endsWith(".kitchenalert")) //not needed, the dialog won't let the user to select files not ending with ".kitchenalert"
493 // filename.append(".kitchenalert");
496 loadTimer(filename,true); //timer gets started
501 void KitchenAlertMainWindow::initializeTimer(Timer *p_timer, bool startImmediately)
507 connect(p_timer,SIGNAL(alert(QModelIndex)),this,SLOT(alert(QModelIndex)));
510 //connect change sound functions
512 connect(this,SIGNAL(defaultSoundEnabled()),p_timer,SLOT(enableDefaultSound()));
513 connect(this,SIGNAL(soundChanged(QString)),p_timer,SLOT(changeAlertSound(QString)));
516 //Disable buttons, as selection is cleared when view is refreshed to show the new timer
518 disableSelectionDependentButtons();
521 // give timers to the model (model wants list of timers now..)
523 QList<Timer *> timerList;
525 timerList.append(p_timer);
526 model_.addTimers(timerList,startImmediately); //timer gets started in the model if startImmediately is true (default)
530 void KitchenAlertMainWindow::openStickyDialog()
532 StickyDialog stickyDialog(defaultSaveDirectory_);
535 if (stickyDialog.exec()== QDialog::Accepted)
538 settings.setValue("sticky",stickyDialog.getStickyList());
542 bool KitchenAlertMainWindow::loadStickies()
544 bool allSuccess = true;
548 QStringList stickies = settings.value("sticky").toStringList();
551 foreach (QString stickyFileName, stickies)
553 if (!loadTimer(stickyFileName,false)) //initializes the timer without starting it
560 bool KitchenAlertMainWindow::loadTimer(QString filename, bool startImmediately)
562 QString errorTitle(tr("Failed to load file "));
563 errorTitle.append(filename);
565 Timer * p_timer = new Timer();
566 if (!p_timer->load(filename))
568 QMessageBox::critical(this,errorTitle,tr("Unable to open file or not a valid KitchenAlert timer file."));
573 initializeTimer(p_timer,startImmediately);