2 Copyright (C) <2010> <Markus Scharnowski markus.scharnowski@gmail.com>
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 3 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, see <http://www.gnu.org/licenses/>.
17 #include <QFileDialog>
18 #include <QMessageBox>
19 #include <QDataStream>
20 #include <QApplication>
22 #include <QInputDialog>
30 #include "mainwindow.h"
31 #include "aboutdialog.hpp"
32 #include "showfulllistdialog.hpp"
37 MainWindow::MainWindow(QWidget *parent) :
40 snprintf(mainButtonStartText,BUFSIZ-1,
42 "If this program is used uncautiously\n"
43 "you could break your device physically.\n"
44 "Always be sure that you use this\n"
45 "software and the corresponding\n"
46 "hardware in a way that the hardware\n"
50 fsExitButton = new FullScreenExitButton(this);
53 timer = new QTimer(this);
54 connect(timer, SIGNAL(timeout()), this, SLOT(mainButtonTimeoutUpdate()));
55 timerRefreshTimeMs = 100;
57 connect(actionReset, SIGNAL(triggered()), this , SLOT(resetProgram()));
58 connect(actionResetFs, SIGNAL(triggered()), this , SLOT(resetProgramAndFullscreen()));
59 // connect(actionResetFs, SIGNAL(triggered()), this , SLOT(actionReset->Trigger));
60 connect(actionSimulated_click, SIGNAL(triggered()), this , SLOT(mainButtonRefresh()));
61 connect(actionPause, SIGNAL(triggered()), this , SLOT(pauseCounting()));
62 connect(actionSave_full_list, SIGNAL(triggered()), this , SLOT(saveToFile()));
63 connect(actionEnable_full_date, SIGNAL(triggered()), this , SLOT(toggleFullDate()));
64 connect(actionEnable_time_and_date, SIGNAL(triggered()), this , SLOT(toggleTimeDate()));
65 connect(actionAbout, SIGNAL(triggered()), this , SLOT(about()));
66 connect(actionShow_full_list, SIGNAL(triggered()), this , SLOT(showFullList()));
67 connect(action_Fullscreen, SIGNAL(triggered()), this, SLOT(showFullScreenHandler()));
68 connect(actionChangeNumberOfLines, SIGNAL(triggered()), this, SLOT(changeNumberOfLines()));
69 connect(actionChangeFontSize, SIGNAL(triggered()), this, SLOT(changeFontSize()));
71 connect(this->mainButton, SIGNAL(clicked()), this, SLOT(mainButtonRefresh()));
73 changeNumberOfLines(8);
78 MainWindow::~MainWindow()
82 int MainWindow::updateTime()
94 void MainWindow::mainButtonRefresh()
97 QString latest = generateHistoryString();
98 QString string = completeString.remove(mainButtonStartText);
100 QString header = getHeaderLine();
107 timer->start(timerRefreshTimeMs);
109 else if(hitCount > 1)
111 if(!timer->isActive())
113 timer->start(timerRefreshTimeMs);
120 mainButtonRefreshTextOnly();
123 lines = string.split("\n");
125 /* add new entry information directly behind the current header
126 wihtout start information if there is any.
128 if(lines.length() > 0)
130 if(lines[0].indexOf("#0") > 0)
132 lines[0].truncate(lines[0].indexOf("#0"));
134 lines[0].append(latest);
137 string = lines.join("\n").prepend("\n").prepend(header);
138 completeString = string;
139 lines = string.split("\n");
140 /* adjust the total number of lines of the button */
141 if(lines.length() > maximumNumberOfLines)
143 while(lines.length() > maximumNumberOfLines
144 && lines.length() > 0)
149 else if(lines.length() < maximumNumberOfLines)
151 while(lines.length() < maximumNumberOfLines)
156 string = lines.join("\n");
157 this->mainButton->setText(tr(string.toStdString().c_str()));
160 std::cout << "---" << std::endl << string.toStdString() << std::endl << "-" << string.split("\n").length() << "-" << std::endl;
164 QString MainWindow::generateHistoryString()
168 std::string previousStr, lastStr, firstStr;
170 previousStr = overallTime.getPreviousTimeString();
171 lastStr = overallTime.getLastTimeString();
172 firstStr = overallTime.getStartTimeString();
174 snprintf(tmp,BUFSIZ-1,
177 // "⅀∑ Total %.3lfs "
182 overallTime.getDeltaLastToPrev(),
183 overallTime.getDeltaLastToStart(),
184 overallTime.getDeltaLastToStart()/(hitCount-1)
189 if(true == timeOutput)
191 result.prepend(lastStr.c_str());
197 int MainWindow::resetCounters()
204 int MainWindow::resetUi()
206 this->mainButton->setText(tr(mainButtonStartText));
207 this->actionPause->setText(tr("&Pause"));
208 this->actionEnable_full_date->setDisabled(true);
210 completeString = this->mainButton->text();
216 void MainWindow::resetProgram()
220 if(timer->isActive())
226 void MainWindow::pauseCounting()
233 int MainWindow::toggleTimer()
235 if(timer->isActive())
241 timer->start(timerRefreshTimeMs);
246 void MainWindow::mainButtonTimeoutUpdate()
248 if(!timer->isActive())
250 assert(0 && "Unintended use");
253 else if(overallTime.isPaused())
259 QString string = this->mainButton->text();
260 QStringList lines = string.split("\n");
261 if(lines.length() >= 1)
263 lines[0] = getHeaderLine();
267 assert(0 && "Lines are missing");
269 this->mainButton->setText(tr(lines.join("\n").toStdString().c_str()));
271 //update stored string
272 lines = completeString.split("\n");
273 if(lines.length() >= 1)
275 lines[0] = getHeaderLine();
277 completeString = lines.join("\n");
280 QString MainWindow::getHeaderLine()
283 std::stringstream sstr;
285 double runTime = overallTime.getDeltaNowToStart();
290 sstr << "#" << hitCount << " ";
291 sstr << std::setfill('0');
292 hours = (int)(runTime/3600);
293 sstr << hours << ":"; //hour
294 time = runTime - 3600*hours;
295 min = (int)(time/60);
296 sstr << std::setw(2) << min << ":"; //minute
297 time = runTime - 3600*hours - 60*min;
298 sstr.setf(std::ios::fixed);
299 sstr.setf(std::ios::showpoint);
301 sstr << time << " "; //seconds
302 if(true == timeOutput)
304 sstr << "#0 " << overallTime.getStartTimeString();
307 headerLine = sstr.str().c_str();
311 void MainWindow::saveToFile()
313 ShowFullListDialog *listHander;
314 listHander = new ShowFullListDialog(0,completeString);
318 int MainWindow::toggleActionPause()
320 QString str = this->actionPause->text();
321 if(str == "&Pause" && overallTime.isPaused())
323 this->actionPause->setText(tr("R&esume"));
327 this->actionPause->setText(tr("&Pause"));
332 int MainWindow::updateUiText()
338 void MainWindow::toggleFullDate()
340 if(overallTime.isDateForStringsEnabled())
342 overallTime.disableDateForStrings();
346 overallTime.enableDateForStrings();
350 void MainWindow::toggleTimeDate()
352 if(this->actionEnable_time_and_date->isChecked())
354 this->actionEnable_full_date->setEnabled(true);
359 this->actionEnable_full_date->setDisabled(true);
364 void MainWindow::about()
366 AboutDialog *pa = new AboutDialog;
367 QTextBrowser *examples = new QTextBrowser;
368 examples->setOpenExternalLinks(true);
370 "<p><b><a href =\"http://sites.google.com/site/markusscharnowski/n/pushit/real-life-examples\">Examples website with videos and pictures.</a></b><p>"
374 "<p><b>Pull ups</b></p>"
375 "<p>Place the phone add the position where you are in the highest position, so you can hit it with your nose. In my case I mount the Nokia N900 above a door with the help of some tesa-strips. I also tried it without tesa-strips but after some pushes on the N900 I was too anxious that it could fall down on the floor. So I recommend some safety mechanism to have fun with your device now and in the future. Every time you pulling yourself up, you touch the screen of the N900 with your nose. So you will always know how many pull ups you have done.</p>"
377 "<p><b>Push ups</b></p>"
378 "<p>Place the smartphone just below your nose so you can hit it with the nose when in the lowest position. And then start pushing up.</p>"
380 "<p><b>Crunches</b></p>"
381 "Doing crunches is a tiny bit more tricky. You have to go into your crunching position (laying on your back, feet up) and place your phone behind your head. Positioned well, you will be able to touch your phone with one of your thumbs every time you are going down (assuming you fold your hands behind your head when doing crunches)."
383 "<p><b>Lower back exercise</b></p>"
384 "<p>Place the phone just below your nose so you can hit it with the nose. I don't know how this exercise is called - if you know it, please let me know it too.<br>"
385 "To execute this exercise I lay myself on some pillows on a bench. My legs will get support by a table. The exercise itself is moving you upper body down to the phone and up again till your back is strait like when your are standing on your feet.</p>"
388 pa->setProgramName(windowTitle());
389 pa->setProgramUrl("http://sites.google.com/site/markusscharnowski/n/pushit");
390 pa->tabs->insertTab(5,examples,tr("&Examples"));
391 pa->setMinimumHeight(400);
396 void MainWindow::showFullList()
398 ShowFullListDialog *ps = new ShowFullListDialog(0,completeString);
402 void MainWindow::showFullScreenHandler()
404 bool isFullScreen = windowState() & Qt::WindowFullScreen;
408 // this->action_Fullscreen->setText(tr("&Fullscreen"));
413 fsExitButton->show();
414 // this->action_Fullscreen->setText(tr("&Disable Fullscreen"));
418 void MainWindow::slotFullscreenExit()
420 action_Fullscreen->trigger();
423 void MainWindow::setupUi()
425 if (this->objectName().isEmpty())
427 this->setObjectName(QString::fromUtf8("MainWindow"));
429 setBaseSize(800,480);
433 mainButton = new QPushButton;
434 mainButton->setObjectName(QString::fromUtf8("mainButton"));
435 QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
436 mainButton->setSizePolicy(sizePolicy);
439 font1.setPointSize(26);
443 mainButton->setFont(font1);
444 mainButton->setAutoFillBackground(true);
445 mainButton->setDefault(true);
446 mainButton->setFlat(true);
447 mainButton->setStyleSheet("text-align:center;");;
451 font.setPointSize(12);
455 centralWidget = new QWidget(this);
456 centralWidget->setObjectName(QString::fromUtf8("centralWidget"));
457 this->setCentralWidget(centralWidget);
459 QHBoxLayout *mainLayout = new QHBoxLayout;
460 mainLayout->addWidget(mainButton);
461 centralWidget->setLayout(mainLayout);
463 /* actions for te menu */
464 actionReset = new QAction(this);
465 actionReset->setObjectName(QString::fromUtf8("actionReset"));
467 actionResetFs = new QAction(this);
468 actionResetFs->setObjectName(QString::fromUtf8("actionResetFs"));
470 actionSimulated_click = new QAction(this);
471 actionSimulated_click->setObjectName(QString::fromUtf8("actionSimulated_click"));
473 actionPause = new QAction(this);
474 actionPause->setObjectName(QString::fromUtf8("actionPause"));
476 actionShow_full_list = new QAction(this);
477 actionShow_full_list->setObjectName(QString::fromUtf8("actionShow_full_list"));
479 actionSave_full_list = new QAction(this);
480 actionSave_full_list->setObjectName(QString::fromUtf8("actionSave_full_list"));
482 actionAbout = new QAction(this);
483 actionAbout->setObjectName(QString::fromUtf8("actionAbout"));
485 actionEnable_full_date = new QAction(this);
486 actionEnable_full_date->setObjectName(QString::fromUtf8("actionEnable_full_date"));
487 actionEnable_full_date->setCheckable(true);
489 actionEnable_time_and_date = new QAction(this);
490 actionEnable_time_and_date->setObjectName(QString::fromUtf8("actionEnable_time_and_date"));
491 actionEnable_time_and_date->setCheckable(true);
493 action_Fullscreen = new QAction(this);
494 action_Fullscreen->setObjectName(QString::fromUtf8("action_Fullscreen"));
495 action_Fullscreen->setCheckable(true);
497 actionChangeNumberOfLines = new QAction(this);
498 actionChangeNumberOfLines->setObjectName(QString::fromUtf8("actionChangeNumberOfLines"));
500 actionChangeFontSize = new QAction(this);
501 actionChangeFontSize->setObjectName(QString::fromUtf8("actionChangeFontSize"));
504 menuBar = new QMenuBar(this);
505 menuBar->setObjectName(QString::fromUtf8("menuBar"));
506 menuBar->setGeometry(QRect(0, 0, 800, 25));
507 menuPush_It_Menu = new QMenu(menuBar);
508 menuPush_It_Menu->setObjectName(QString::fromUtf8("menuPush_It_Menu"));
509 menuHelp = new QMenu(menuBar);
510 menuHelp->setObjectName(QString::fromUtf8("menuHelp"));
511 menuData = new QMenu(menuBar);
512 menuData->setObjectName(QString::fromUtf8("menuData"));
513 menuView = new QMenu(menuBar);
514 menuView->setObjectName(QString::fromUtf8("menuView"));
515 this->setMenuBar(menuBar);
517 menuBar->addAction(menuPush_It_Menu->menuAction());
518 menuBar->addAction(menuView->menuAction());
519 menuBar->addAction(menuData->menuAction());
520 menuBar->addAction(menuHelp->menuAction());
521 menuPush_It_Menu->addAction(actionReset);
522 menuPush_It_Menu->addAction(actionPause);
523 menuPush_It_Menu->addAction(actionSimulated_click);
524 menuHelp->addAction(actionAbout);
525 menuData->addAction(actionEnable_time_and_date);
526 menuData->addAction(actionEnable_full_date);
527 menuData->addSeparator();
528 menuData->addAction(actionSave_full_list);
529 menuData->addAction(actionShow_full_list);
530 menuView->addAction(action_Fullscreen);
531 menuView->addAction(actionResetFs);
532 menuView->addAction(actionChangeNumberOfLines);
533 menuView->addAction(actionChangeFontSize);
537 QMetaObject::connectSlotsByName(this);
540 void MainWindow::retranslateUi()
542 this->setWindowTitle(QApplication::translate("MainWindow", "Push It!", 0, QApplication::UnicodeUTF8));
543 actionReset->setText(QApplication::translate("MainWindow", "&Reset", 0, QApplication::UnicodeUTF8));
544 actionResetFs->setText(QApplication::translate("MainWindow", "&Reset+Fullscreen", 0, QApplication::UnicodeUTF8));
545 actionSimulated_click->setText(QApplication::translate("MainWindow", "Push &it!", 0, QApplication::UnicodeUTF8));
546 actionPause->setText(QApplication::translate("MainWindow", "&Pause", 0, QApplication::UnicodeUTF8));
547 actionShow_full_list->setText(QApplication::translate("MainWindow", "Show full &list", 0, QApplication::UnicodeUTF8));
548 actionSave_full_list->setText(QApplication::translate("MainWindow", "&Save full list", 0, QApplication::UnicodeUTF8));
549 actionAbout->setText(QApplication::translate("MainWindow", "&About", 0, QApplication::UnicodeUTF8));
550 actionEnable_full_date->setText(QApplication::translate("MainWindow", "Enable &full date", 0, QApplication::UnicodeUTF8));
551 actionEnable_time_and_date->setText(QApplication::translate("MainWindow", "Enable &time and date", 0, QApplication::UnicodeUTF8));
552 action_Fullscreen->setText(QApplication::translate("MainWindow", "&Fullscreen", 0, QApplication::UnicodeUTF8));
553 actionChangeNumberOfLines->setText(QApplication::translate("MainWindow", "&Lines", 0, QApplication::UnicodeUTF8));
554 actionChangeFontSize->setText(QApplication::translate("MainWindow", "Font &size", 0, QApplication::UnicodeUTF8));
555 mainButton->setText(QApplication::translate("MainWindow", "Start", 0, QApplication::UnicodeUTF8));
556 menuPush_It_Menu->setTitle(QApplication::translate("MainWindow", "&Counter", 0, QApplication::UnicodeUTF8));
557 menuHelp->setTitle(QApplication::translate("MainWindow", "&Help", 0, QApplication::UnicodeUTF8));
558 menuData->setTitle(QApplication::translate("MainWindow", "&Data", 0, QApplication::UnicodeUTF8));
559 menuView->setTitle(QApplication::translate("MainWindow", "&View", 0, QApplication::UnicodeUTF8));
562 void MainWindow::changeNumberOfLines(int number)
568 number = QInputDialog::getInt(this, tr("Lines"),
569 tr("Number of lines to be displayed:"),
570 maximumNumberOfLines, 0, maxLines, 1,
578 else if (number > 0 && number < maxLines)
580 maximumNumberOfLines = number;
585 text.sprintf("Invalid entry. Try something like \"4\" (max %i).",maxLines);
586 QMessageBox::information(this, tr("Invalid entry"),
587 tr(text.toStdString().c_str()));
591 QString actionText = actionChangeNumberOfLines->text();
592 actionText = "&Lines (";
593 actionText += QString::number(maximumNumberOfLines);
595 actionChangeNumberOfLines->setText(actionText);
596 mainButtonRefreshTextOnly();
599 void MainWindow::changeFontSize(int size)
603 QFont font = mainButton->font();
606 size = QInputDialog::getInt(this, tr("Font size"),
608 font.pointSize(), 0, maxSize, 1,
620 else if (size > 0 && size < maxSize)
622 font.setPointSize(size);
623 mainButton->setFont(font);
628 text.sprintf("Invalid entry. Try something like \"28\" (max %i).",maxSize);
629 QMessageBox::information(this, tr("Invalid entry"),
630 tr(text.toStdString().c_str()));
634 QString actionText = actionChangeFontSize->text();
635 actionText = "Font &size (";
636 actionText += QString::number(size);
638 actionChangeFontSize->setText(actionText);
639 mainButtonRefreshTextOnly();
643 function to use when the text itself is not changed but the number of lines or
644 the formatting of the text
646 void MainWindow::mainButtonRefreshTextOnly()
648 QString string = completeString;
653 string = getHeaderLine();
656 lines = string.split("\n");
658 /* adjust the total number of lines of the button */
659 if(lines.length() > maximumNumberOfLines)
661 while(lines.length() > maximumNumberOfLines
662 && lines.length() > 0)
667 else if(lines.length() < maximumNumberOfLines)
669 while(lines.length() < maximumNumberOfLines)
675 string = lines.join("\n");
676 this->mainButton->setText(tr(string.toStdString().c_str()));
679 void MainWindow::resetProgramAndFullscreen()
682 action_Fullscreen->trigger();