2 * Copyright (C) 2009 Sakari Poussa
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, version 2.
11 #include <QMaemo5InformationBox>
14 #include "score-common.h"
15 #include "main-window.h"
16 #include "score-dialog.h"
17 #include "course-dialog.h"
18 #include "settings-dialog.h"
19 #include "stat-model.h"
20 #include "xml-dom-parser.h"
22 QString appName("scorecard");
23 QString topDir("/opt");
24 QString mmcDir("/media/mmc1");
25 QString dataDirName("data");
27 QString imgDir(topDir + "/pixmaps");
28 QString scoreFileName("score.xml");
30 QString clubFileName("club.xml");
32 QString masterFileName("club-master.xml");
34 QString logFile("/tmp/scorecard.log");
35 QString titleScores("ScoreCard - Scores");
36 QString titleCourses("ScoreCard - Courses");
37 QString settingsGroup("Settings");
38 QString settingsHcp("hcp");
39 QString settingsHomeClub("home-club");
40 QString settingsDefaultCourses("default-courses");
42 bool dateLessThan(const Score *s1, const Score *s2)
47 bool dateMoreThan(const Score *s1, const Score *s2)
51 // Find score based on club and course name
52 Score *MainWindow::findScore(QString & clubName, QString & courseName)
54 QListIterator<Score *> i(scoreList);
59 if ((s->getClubName() == clubName) &&
60 (s->getCourseName() == courseName))
66 // Find club based on name
67 Club *MainWindow::findClub(QString &name)
69 QListIterator<Club *> i(clubList);
74 if (c->getName() == name)
80 // Find course based on club & course name
81 Course *MainWindow::findCourse(const QString &clubName,
82 const QString &courseName)
84 QListIterator<Club *> i(clubList);
89 if (c->getName() == clubName) {
90 return c->getCourse(courseName);
96 // Find course based on current selection on the list
97 // TODO: make sure this is only called when course list is the model...
98 Course *MainWindow::findCourse()
100 QModelIndex index = selectionModel->currentIndex();
101 const QAbstractItemModel *model = selectionModel->model();
102 QString str = model->data(index, Qt::DisplayRole).toString();
104 QStringList strList = str.split(",");
105 if (strList.count() != 2) {
106 showNote(tr("Invalid course selection"));
109 return findCourse(strList[0], strList[1]);
112 void MainWindow::flushReadOnlyItems()
114 QMutableListIterator<Club *> i(clubList);
117 while (i.hasNext()) {
119 if (c->isReadOnly()) {
120 qDebug() << "Del:" << c->getName();
127 MainWindow::MainWindow(QMainWindow *parent): QMainWindow(parent)
132 setAttribute(Qt::WA_Maemo5StackedWindow);
137 centralWidget = new QWidget(this);
139 setCentralWidget(centralWidget);
141 loadScoreFile(scoreFile, scoreList);
142 if (conf.defaultCourses == "Yes")
143 loadClubFile(masterFile, clubList, true);
144 loadClubFile(clubFile, clubList);
146 // Sort the scores based on dates
147 qSort(scoreList.begin(), scoreList.end(), dateMoreThan);
151 createListView(scoreList, clubList);
153 createLayoutList(centralWidget);
156 void MainWindow::loadSettings(void)
158 bool external = false;
164 // TODO: make via user option, automatic will never work
168 dataDir = "./" + dataDirName;
171 dataDir = mmcDir + "/" + appName + "/" + dataDirName;
174 dataDir = topDir + "/" + appName + "/" + dataDirName;
177 scoreFile = dataDir + "/" + scoreFileName;
178 clubFile = dataDir + "/" + clubFileName;
179 masterFile = dataDir + "/" + masterFileName;
183 if (!dir.mkpath(dataDir)) {
184 qWarning() << "Unable to create: " + dataDir;
187 qDebug() << "Data is at:" + dataDir;
189 settings.beginGroup(settingsGroup);
190 conf.hcp = settings.value(settingsHcp);
191 conf.homeClub = settings.value(settingsHomeClub);
192 conf.defaultCourses = settings.value(settingsDefaultCourses);
195 // Use default courses if no settings for that
196 if (!conf.defaultCourses.isValid())
197 conf.defaultCourses = "Yes";
199 qDebug() << "Settings: " << conf.hcp << conf.homeClub << conf.defaultCourses;
202 void MainWindow::saveSettings(void)
204 settings.beginGroup(settingsGroup);
205 if (conf.hcp.isValid())
206 settings.setValue(settingsHcp, conf.hcp);
207 if (conf.homeClub.isValid())
208 settings.setValue(settingsHomeClub, conf.homeClub);
209 if (conf.defaultCourses.isValid())
210 settings.setValue(settingsDefaultCourses, conf.defaultCourses);
214 void MainWindow::createLayoutList(QWidget *parent)
216 QVBoxLayout * tableLayout = new QVBoxLayout;
217 tableLayout->addWidget(list);
219 QHBoxLayout *mainLayout = new QHBoxLayout(parent);
220 mainLayout->addLayout(tableLayout);
221 parent->setLayout(mainLayout);
224 void MainWindow::createListView(QList<Score *> &scoreList,
225 QList <Club *> &clubList)
227 list = new QListView(this);
229 scoreListModel = new ScoreListModel(scoreList, clubList);
230 courseListModel = new CourseListModel(clubList);
232 list->setStyleSheet(ScoreStyle::style());
234 list->setSelectionMode(QAbstractItemView::SingleSelection);
235 list->setProperty("FingerScrolling", true);
240 connect(list, SIGNAL(clicked(QModelIndex)),
241 this, SLOT(clickedList(QModelIndex)));
244 void MainWindow::listScores()
246 list->setModel(scoreListModel);
247 selectionModel = list->selectionModel();
248 updateTitleBar(titleScores);
251 void MainWindow::listCourses()
253 list->setModel(courseListModel);
254 selectionModel = list->selectionModel();
255 updateTitleBar(titleCourses);
258 void MainWindow::createActions()
260 newScoreAction = new QAction(tr("New Score"), this);
261 connect(newScoreAction, SIGNAL(triggered()), this, SLOT(newScore()));
263 newCourseAction = new QAction(tr("New Course"), this);
264 connect(newCourseAction, SIGNAL(triggered()), this, SLOT(newCourse()));
266 statAction = new QAction(tr("Statistics"), this);
267 connect(statAction, SIGNAL(triggered()), this, SLOT(viewStatistics()));
269 settingsAction = new QAction(tr("Settings"), this);
270 connect(settingsAction, SIGNAL(triggered()), this, SLOT(viewSettings()));
272 // Maemo5 style menu filters
273 filterGroup = new QActionGroup(this);
274 filterGroup->setExclusive(true);
276 listScoreAction = new QAction(tr("Scores"), filterGroup);
277 listScoreAction->setCheckable(true);
278 listScoreAction->setChecked(true);
279 connect(listScoreAction, SIGNAL(triggered()), this, SLOT(listScores()));
281 listCourseAction = new QAction(tr("Courses"), filterGroup);
282 listCourseAction->setCheckable(true);
283 connect(listCourseAction, SIGNAL(triggered()), this, SLOT(listCourses()));
286 void MainWindow::createMenus()
289 menu = menuBar()->addMenu("");
291 menu = menuBar()->addMenu("Menu");
294 menu->addAction(newScoreAction);
295 menu->addAction(newCourseAction);
296 menu->addAction(statAction);
297 menu->addAction(settingsAction);
298 menu->addActions(filterGroup->actions());
301 void MainWindow::updateTitleBar(QString & msg)
306 void MainWindow::showNote(QString msg)
309 QMaemo5InformationBox::information(this,
311 QMaemo5InformationBox::DefaultTimeout);
315 void MainWindow::clickedList(const QModelIndex &index)
317 int row = index.row();
319 const QAbstractItemModel *m = index.model();
320 if (m == scoreListModel) {
321 if (row < scoreList.count()) {
322 Score * score = scoreList.at(row);
323 Course * course = findCourse(score->getClubName(), score->getCourseName());
324 viewScore(score, course);
327 else if (m == courseListModel) {
328 QString str = courseListModel->data(index, Qt::DisplayRole).toString();
329 QStringList strList = str.split(",");
331 if (strList.count() != 2) {
332 showNote(QString("Invalid course selection"));
335 Course * course = findCourse(strList.at(0), strList.at(1));
341 void MainWindow::newCourse()
343 CourseSelectDialog *selectDialog = new CourseSelectDialog(this);
345 int result = selectDialog->exec();
351 selectDialog->results(clubName, courseName);
353 CourseDialog *courseDialog = new CourseDialog(this);
354 courseDialog->init();
355 QString title = "New Course: " + clubName + "," + courseName;
356 courseDialog->setWindowTitle(title);
358 int result = courseDialog->exec();
360 QVector<QString> par(18);
361 QVector<QString> hcp(18);
362 QVector<QString> len(18);
364 courseDialog->results(par, hcp, len);
367 Club *club = findClub(clubName);
369 course = club->getCourse(courseName);
371 showNote(tr("Club/course already in the database"));
375 course = new Course(courseName, par, hcp);
376 club->addCourse(course);
380 // New club and course
381 club = new Club(clubName);
382 course = new Course(courseName, par, hcp);
383 club->addCourse(course);
387 saveClubFile(clubFile, clubList);
388 courseListModel->update(clubList);
394 void MainWindow::deleteCourse()
396 Course * course = findCourse();
397 Club * club = course->parent();
399 // Can not delete course if it has scores -- check
400 if (findScore(club->getName(), course->getName()) != 0) {
401 showNote(tr("Can not delete course, delete scores on the course first"));
408 club->delCourse(course);
410 if (club->isEmpty()) {
411 int index = clubList.indexOf(club);
413 clubList.removeAt(index);
417 saveClubFile(clubFile, clubList);
418 courseListModel->update(clubList);
422 void MainWindow::editCourse()
424 Course *course = findCourse();
427 showNote(tr("No course on edit"));
431 CourseDialog *courseDialog = new CourseDialog(this);
432 courseDialog->init(course);
434 QString title = "Edit Course: " + course->getName();
435 courseDialog->setWindowTitle(title);
437 int result = courseDialog->exec();
439 QVector<QString> par(18);
440 QVector<QString> hcp(18);
441 QVector<QString> len(18);
443 courseDialog->results(par, hcp, len);
445 course->update(par, hcp, len);
446 saveClubFile(clubFile, clubList);
450 void MainWindow::newScore()
452 SelectDialog *selectDialog = new SelectDialog(this);
454 selectDialog->init(clubList);
456 int result = selectDialog->exec();
462 selectDialog->results(clubName, courseName, date);
464 ScoreDialog *scoreDialog = new ScoreDialog(this);
465 QString title = "New Score: " + courseName + ", " + date;
466 scoreDialog->setWindowTitle(title);
468 Club *club = findClub(clubName);
470 showNote(tr("Error: no such club"));
473 Course *course = club->getCourse(courseName);
475 showNote(tr("Error: no such course:"));
478 scoreDialog->init(course);
479 result = scoreDialog->exec();
481 QVector<QString> scores(18);
483 scoreDialog->results(scores);
484 Score *score = new Score(scores, clubName, courseName, date);
487 // Sort the scores based on dates
488 qSort(scoreList.begin(), scoreList.end(), dateMoreThan);
490 saveScoreFile(scoreFile, scoreList);
491 scoreListModel->update(scoreList);
497 void MainWindow::deleteScore()
502 QModelIndex index = selectionModel->currentIndex();
503 scoreList.removeAt(index.row());
505 saveScoreFile(scoreFile, scoreList);
506 scoreListModel->update(scoreList);
510 void MainWindow::editScore()
512 QModelIndex index = selectionModel->currentIndex();
513 Score * score = scoreList.at(index.row());
516 course = findCourse(score->getClubName(), score->getCourseName());
518 if (!course || !score) {
519 qDebug() << "No score/course to edit";
523 QString date = score->getDate();
525 ScoreDialog *scoreDialog = new ScoreDialog;
527 QString title = "Edit Score: " + course->getName() + ", " + date;
528 scoreDialog->setWindowTitle(title);
530 scoreDialog->init(course, score);
532 int result = scoreDialog->exec();
535 QVector<QString> scores(18);
537 scoreDialog->results(scores);
539 score->update(scores);
541 // Sort the scores based on dates
542 qSort(scoreList.begin(), scoreList.end(), dateMoreThan);
544 saveScoreFile(scoreFile, scoreList);
546 scoreListModel->update(scoreList);
550 void MainWindow::viewScore(Score * score, Course * course)
552 scoreWin = new QMainWindow(this);
553 QString title = QString("Score: %1, %2 - %3").arg(score->getClubName()).arg(score->getCourseName()).arg(score->getDate());
554 scoreWin->setWindowTitle(title);
556 scoreWin->setAttribute(Qt::WA_Maemo5StackedWindow);
559 QAction *editAction = new QAction(tr("Edit"), scoreWin);
560 connect(editAction, SIGNAL(triggered()), this, SLOT(editScore()));
561 scoreWin->menuBar()->addAction(editAction);
563 QAction *delAction = new QAction(tr("Delete"), scoreWin);
564 connect(delAction, SIGNAL(triggered()), this, SLOT(deleteScore()));
565 scoreWin->menuBar()->addAction(delAction);
567 ScoreTableModel *model = new ScoreTableModel(score, course);
569 QTableView * table = new QTableView;
571 table->setSelectionMode(QAbstractItemView::NoSelection);
572 table->setStyleSheet(ScoreStyle::style());
573 table->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
574 table->verticalHeader()->setResizeMode(QHeaderView::Stretch);
575 table->horizontalHeader()->hide();
576 table->setModel(model);
578 QWidget *central = new QWidget(scoreWin);
579 scoreWin->setCentralWidget(central);
581 QVBoxLayout *layout = new QVBoxLayout;
582 layout->addWidget(table);
584 central->setLayout(layout);
588 void MainWindow::viewCourse(Course * course)
590 courseWin = new QMainWindow(this);
591 QString title = QString("Course: %1, Par - %2").arg(course->getName()).arg(course->getTotal(Total));
592 courseWin->setWindowTitle(title);
594 courseWin->setAttribute(Qt::WA_Maemo5StackedWindow);
597 QAction *editAction = new QAction(tr("Edit"), courseWin);
598 connect(editAction, SIGNAL(triggered()), this, SLOT(editCourse()));
599 courseWin->menuBar()->addAction(editAction);
601 QAction *delAction = new QAction(tr("Delete"), courseWin);
602 connect(delAction, SIGNAL(triggered()), this, SLOT(deleteCourse()));
603 courseWin->menuBar()->addAction(delAction);
605 CourseTableModel *model = new CourseTableModel(course);
607 QTableView * table = new QTableView;
609 table->setSelectionMode(QAbstractItemView::NoSelection);
610 //table->setStyleSheet(ScoreStyle::headerView());
611 table->setStyleSheet(ScoreStyle::style());
612 table->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
613 table->verticalHeader()->setResizeMode(QHeaderView::Stretch);
614 table->horizontalHeader()->hide();
615 table->setModel(model);
617 QWidget *central = new QWidget(courseWin);
618 courseWin->setCentralWidget(central);
620 QVBoxLayout *layout = new QVBoxLayout;
621 layout->addWidget(table);
623 central->setLayout(layout);
627 void MainWindow::viewStatistics()
629 QMainWindow *win = new QMainWindow(this);
630 QString title = "Statistics";
631 win->setWindowTitle(title);
633 win->setAttribute(Qt::WA_Maemo5StackedWindow);
636 StatModel *model = new StatModel(clubList, scoreList);
638 QTableView *table = new QTableView;
640 table->setSelectionMode(QAbstractItemView::NoSelection);
641 table->setStyleSheet(ScoreStyle::style());
642 table->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
643 table->verticalHeader()->setResizeMode(QHeaderView::Stretch);
644 table->verticalHeader()->setAutoFillBackground(true);
645 table->setModel(model);
647 QWidget *central = new QWidget(win);
648 win->setCentralWidget(central);
650 QTextEdit *textEdit = new QTextEdit;
652 textEdit->setReadOnly(true);
654 QVBoxLayout *infoLayout = new QVBoxLayout;
655 infoLayout->addWidget(table);
657 QHBoxLayout *mainLayout = new QHBoxLayout(central);
658 mainLayout->addLayout(infoLayout);
659 central->setLayout(mainLayout);
664 void MainWindow::viewSettings()
666 SettingsDialog *dlg = new SettingsDialog(this);
668 dlg->init(conf, clubList);
670 int result = dlg->exec();
672 QString oldValue = conf.defaultCourses.toString();
674 QString newValue = conf.defaultCourses.toString();
677 qDebug() << "Settings:" << oldValue << "->" << newValue;
679 // Reload club list, or drop r/o courses from list
680 if (oldValue == "Yes" && newValue == "No") {
681 flushReadOnlyItems();
682 courseListModel->update(clubList);
685 else if ((oldValue == "No" || oldValue == "") && newValue == "Yes") {
686 loadClubFile(masterFile, clubList, true);
687 courseListModel->update(clubList);
693 void MainWindow::loadScoreFile(QString &fileName, QList<Score *> &list)
695 ScoreXmlHandler handler(list);
697 if (handler.parse(fileName))
698 qDebug() << "File loaded:" << fileName << " entries:" << list.size();
701 void MainWindow::saveScoreFile(QString &fileName, QList<Score *> &list)
703 ScoreXmlHandler handler(list);
705 if (handler.save(fileName))
707 qDebug() << "File saved:" << fileName << " entries:" << list.size();
709 qWarning() << "Unable to save:" << fileName;
712 void MainWindow::loadClubFile(QString &fileName, QList<Club *> &list, bool readOnly)
714 ClubXmlHandler handler(list);
716 if (handler.parse(fileName, readOnly))
717 qDebug() << "File loaded:" << fileName << " entries:" << list.size();
720 void MainWindow::saveClubFile(QString &fileName, QList<Club *> &list)
722 ClubXmlHandler handler(list);
724 if (handler.save(fileName))
726 qDebug() << "File saved:" << fileName << " entries:" << list.size();
728 qWarning() << "Unable to save:" << fileName;