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)
55 QListIterator<Score *> i(scoreList);
60 if ((s->getClubName() == clubName) &&
61 (s->getCourseName() == courseName))
67 // Find club based on name
68 Club *MainWindow::findClub(QString &name)
71 QListIterator<Club *> i(clubList);
76 if (c->getName() == name)
82 // Find course based on club & course name
83 Course *MainWindow::findCourse(const QString &clubName,
84 const QString &courseName)
87 QListIterator<Club *> i(clubList);
92 if (c->getName() == clubName) {
93 return c->getCourse(courseName);
99 // Find course based on current selection on the list
100 // TODO: make sure this is only called when course list is the model...
101 Course *MainWindow::currentCourse()
104 QModelIndex index = selectionModel->currentIndex();
106 if (!index.isValid())
109 const QAbstractItemModel *model = selectionModel->model();
110 QString str = model->data(index, Qt::DisplayRole).toString();
112 QStringList strList = str.split(", ");
113 if (strList.count() != 2) {
114 showNote(tr("Invalid course selection"));
117 return findCourse(strList[0], strList[1]);
120 // Find score based on current selection on the list
121 // TODO: make sure this is only called when score list is the model...
122 Score *MainWindow::currentScore()
125 QModelIndex index = selectionModel->currentIndex();
127 if (!index.isValid())
130 return scoreList.at(index.row());
133 void MainWindow::flushReadOnlyItems()
136 QMutableListIterator<Club *> i(clubList);
139 while (i.hasNext()) {
141 if (c->isReadOnly()) {
142 qDebug() << "Del:" << c->getName();
149 MainWindow::MainWindow(QMainWindow *parent): QMainWindow(parent)
154 setAttribute(Qt::WA_Maemo5StackedWindow);
159 centralWidget = new QWidget(this);
161 setCentralWidget(centralWidget);
163 loadScoreFile(scoreFile, scoreList);
164 if (conf.defaultCourses == "Yes")
165 loadClubFile(masterFile, clubList, true);
166 loadClubFile(clubFile, clubList);
168 // Sort the scores based on dates
169 qSort(scoreList.begin(), scoreList.end(), dateMoreThan);
173 createListView(scoreList, clubList);
175 createLayoutList(centralWidget);
177 scoreWindow = new ScoreWindow(this);
178 courseWindow = new CourseWindow(this);
181 void MainWindow::loadSettings(void)
184 bool external = false;
190 // TODO: make via user option, automatic will never work
194 dataDir = "./" + dataDirName;
197 dataDir = mmcDir + "/" + appName + "/" + dataDirName;
200 dataDir = topDir + "/" + appName + "/" + dataDirName;
203 scoreFile = dataDir + "/" + scoreFileName;
204 clubFile = dataDir + "/" + clubFileName;
205 masterFile = dataDir + "/" + masterFileName;
209 if (!dir.mkpath(dataDir)) {
210 qWarning() << "Unable to create: " + dataDir;
213 qDebug() << "Data is at:" + dataDir;
215 settings.beginGroup(settingsGroup);
216 conf.hcp = settings.value(settingsHcp);
217 conf.homeClub = settings.value(settingsHomeClub);
218 conf.defaultCourses = settings.value(settingsDefaultCourses);
221 // Use default courses if no settings for that
222 if (!conf.defaultCourses.isValid())
223 conf.defaultCourses = "Yes";
225 qDebug() << "Settings: " << conf.hcp << conf.homeClub << conf.defaultCourses;
228 void MainWindow::saveSettings(void)
231 settings.beginGroup(settingsGroup);
232 if (conf.hcp.isValid())
233 settings.setValue(settingsHcp, conf.hcp);
234 if (conf.homeClub.isValid())
235 settings.setValue(settingsHomeClub, conf.homeClub);
236 if (conf.defaultCourses.isValid())
237 settings.setValue(settingsDefaultCourses, conf.defaultCourses);
241 void MainWindow::createLayoutList(QWidget *parent)
244 QVBoxLayout * tableLayout = new QVBoxLayout;
245 tableLayout->addWidget(list);
247 QHBoxLayout *mainLayout = new QHBoxLayout(parent);
248 mainLayout->addLayout(tableLayout);
249 parent->setLayout(mainLayout);
252 void MainWindow::createListView(QList<Score *> &scoreList,
253 QList <Club *> &clubList)
256 list = new QListView(this);
258 scoreListModel = new ScoreListModel(scoreList, clubList);
259 courseListModel = new CourseListModel(clubList);
261 list->setStyleSheet(ScoreStyle::style());
263 list->setSelectionMode(QAbstractItemView::SingleSelection);
264 list->setProperty("FingerScrolling", true);
269 connect(list, SIGNAL(clicked(QModelIndex)),
270 this, SLOT(clickedList(QModelIndex)));
273 void MainWindow::listScores()
276 list->setModel(scoreListModel);
277 selectionModel = list->selectionModel();
278 updateTitleBar(titleScores);
281 void MainWindow::listCourses()
284 list->setModel(courseListModel);
285 selectionModel = list->selectionModel();
286 updateTitleBar(titleCourses);
289 void MainWindow::createActions()
292 newScoreAction = new QAction(tr("New Score"), this);
293 connect(newScoreAction, SIGNAL(triggered()), this, SLOT(newScore()));
295 newCourseAction = new QAction(tr("New Course"), this);
296 connect(newCourseAction, SIGNAL(triggered()), this, SLOT(newCourse()));
298 statAction = new QAction(tr("Statistics"), this);
299 connect(statAction, SIGNAL(triggered()), this, SLOT(viewStatistics()));
301 settingsAction = new QAction(tr("Settings"), this);
302 connect(settingsAction, SIGNAL(triggered()), this, SLOT(viewSettings()));
304 // Maemo5 style menu filters
305 filterGroup = new QActionGroup(this);
306 filterGroup->setExclusive(true);
308 listScoreAction = new QAction(tr("Scores"), filterGroup);
309 listScoreAction->setCheckable(true);
310 listScoreAction->setChecked(true);
311 connect(listScoreAction, SIGNAL(triggered()), this, SLOT(listScores()));
313 listCourseAction = new QAction(tr("Courses"), filterGroup);
314 listCourseAction->setCheckable(true);
315 connect(listCourseAction, SIGNAL(triggered()), this, SLOT(listCourses()));
318 void MainWindow::createMenus()
322 menu = menuBar()->addMenu("");
324 menu = menuBar()->addMenu("Menu");
327 menu->addAction(newScoreAction);
328 menu->addAction(newCourseAction);
329 menu->addAction(statAction);
330 menu->addAction(settingsAction);
331 menu->addActions(filterGroup->actions());
334 void MainWindow::updateTitleBar(QString & msg)
340 void MainWindow::showNote(QString msg)
343 QMaemo5InformationBox::information(this,
345 QMaemo5InformationBox::DefaultTimeout);
349 void MainWindow::clickedList(const QModelIndex &index)
352 int row = index.row();
354 const QAbstractItemModel *m = index.model();
355 if (m == scoreListModel) {
356 if (row < scoreList.count()) {
357 Score * score = scoreList.at(row);
358 Course * course = findCourse(score->getClubName(), score->getCourseName());
359 viewScore(score, course);
362 else if (m == courseListModel) {
363 QString str = courseListModel->data(index, Qt::DisplayRole).toString();
364 QStringList strList = str.split(", ");
366 if (strList.count() != 2) {
367 showNote(QString("Invalid course selection"));
370 Course * course = findCourse(strList.at(0), strList.at(1));
375 void MainWindow::viewScore(Score * score, Course * course)
378 scoreWindow->setup(score, course);
382 void MainWindow::newScore()
385 SelectDialog *selectDialog = new SelectDialog(this);
387 selectDialog->init(clubList);
389 int result = selectDialog->exec();
395 selectDialog->results(clubName, courseName, date);
397 ScoreDialog *scoreDialog = new ScoreDialog(this);
398 QString title = "New Score: " + courseName + ", " + date;
399 scoreDialog->setWindowTitle(title);
401 Club *club = findClub(clubName);
403 showNote(tr("Error: no such club"));
406 Course *course = club->getCourse(courseName);
408 showNote(tr("Error: no such course:"));
411 scoreDialog->init(course);
412 result = scoreDialog->exec();
414 QVector<QString> scores(18);
416 scoreDialog->results(scores);
417 Score *score = new Score(scores, clubName, courseName, date);
420 // Sort the scores based on dates
421 qSort(scoreList.begin(), scoreList.end(), dateMoreThan);
423 saveScoreFile(scoreFile, scoreList);
424 scoreListModel->update(scoreList);
430 void MainWindow::editScore()
434 Score *score = currentScore();
437 course = findCourse(score->getClubName(), score->getCourseName());
439 if (!course || !score) {
440 qDebug() << "No score/course to edit";
444 QString date = score->getDate();
446 ScoreDialog *scoreDialog = new ScoreDialog(this);
447 scoreDialog->init(course, score);
449 QString title = "Edit Score: " + course->getName() + ", " + date;
450 scoreDialog->setWindowTitle(title);
452 int result = scoreDialog->exec();
454 QVector<QString> scores(18);
456 scoreDialog->results(scores);
458 score->update(scores);
460 // Sort the scores based on dates
461 qSort(scoreList.begin(), scoreList.end(), dateMoreThan);
463 saveScoreFile(scoreFile, scoreList);
469 void MainWindow::deleteScore()
473 scoreWindow->close();
475 QModelIndex index = selectionModel->currentIndex();
476 if (!index.isValid()) {
477 qDebug() << "Invalid index";
481 scoreList.removeAt(index.row());
483 saveScoreFile(scoreFile, scoreList);
484 scoreListModel->update(scoreList);
488 void MainWindow::viewCourse(Course * course)
491 courseWindow->setup(course);
492 courseWindow->show();
495 void MainWindow::newCourse()
498 CourseSelectDialog *selectDialog = new CourseSelectDialog(this);
500 int result = selectDialog->exec();
506 selectDialog->results(clubName, courseName);
508 CourseDialog *courseDialog = new CourseDialog(this);
509 courseDialog->init();
510 QString title = "New Course: " + clubName + "," + courseName;
511 courseDialog->setWindowTitle(title);
513 int result = courseDialog->exec();
515 QVector<QString> par(18);
516 QVector<QString> hcp(18);
517 QVector<QString> len(18);
519 courseDialog->results(par, hcp, len);
522 Club *club = findClub(clubName);
524 course = club->getCourse(courseName);
526 showNote(tr("Club/course already in the database"));
530 course = new Course(courseName, par, hcp);
531 club->addCourse(course);
535 // New club and course
536 club = new Club(clubName);
537 course = new Course(courseName, par, hcp);
538 club->addCourse(course);
542 saveClubFile(clubFile, clubList);
543 courseListModel->update(clubList);
549 void MainWindow::editCourse()
552 Course *course = currentCourse();
555 showNote(tr("No course on edit"));
559 CourseDialog *courseDialog = new CourseDialog(this);
560 courseDialog->init(course);
562 QString title = "Edit Course: " + course->getName();
563 courseDialog->setWindowTitle(title);
565 int result = courseDialog->exec();
567 QVector<QString> par(18);
568 QVector<QString> hcp(18);
569 QVector<QString> len(18);
571 courseDialog->results(par, hcp, len);
573 course->update(par, hcp, len);
574 saveClubFile(clubFile, clubList);
580 void MainWindow::deleteCourse()
584 Course * course = currentCourse();
587 qDebug() << "Invalid course for deletion";
590 club = course->parent();
592 // Can not delete course if it has scores -- check
593 if (findScore(club->getName(), course->getName()) != 0) {
594 showNote(tr("Can not delete course, delete scores on the course first"));
599 courseWindow->close();
601 club->delCourse(course);
603 if (club->isEmpty()) {
604 int index = clubList.indexOf(club);
606 clubList.removeAt(index);
610 saveClubFile(clubFile, clubList);
611 courseListModel->update(clubList);
615 void MainWindow::viewStatistics()
618 QMainWindow *win = new QMainWindow(this);
619 QString title = "Statistics";
620 win->setWindowTitle(title);
622 win->setAttribute(Qt::WA_Maemo5StackedWindow);
625 StatModel *model = new StatModel(clubList, scoreList);
627 QTableView *table = new QTableView;
629 table->setSelectionMode(QAbstractItemView::NoSelection);
630 table->setStyleSheet(ScoreStyle::style());
631 table->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
632 table->verticalHeader()->setResizeMode(QHeaderView::Stretch);
633 table->verticalHeader()->setAutoFillBackground(true);
634 table->setModel(model);
636 QWidget *central = new QWidget(win);
637 win->setCentralWidget(central);
639 QTextEdit *textEdit = new QTextEdit;
641 textEdit->setReadOnly(true);
643 QVBoxLayout *infoLayout = new QVBoxLayout;
644 infoLayout->addWidget(table);
646 QHBoxLayout *mainLayout = new QHBoxLayout(central);
647 mainLayout->addLayout(infoLayout);
648 central->setLayout(mainLayout);
653 void MainWindow::viewSettings()
656 SettingsDialog *dlg = new SettingsDialog(this);
658 dlg->init(conf, clubList);
660 int result = dlg->exec();
662 QString oldValue = conf.defaultCourses.toString();
664 QString newValue = conf.defaultCourses.toString();
667 qDebug() << "Settings:" << oldValue << "->" << newValue;
669 // Reload club list, or drop r/o courses from list
670 if (oldValue == "Yes" && newValue == "No") {
671 flushReadOnlyItems();
672 courseListModel->update(clubList);
675 else if ((oldValue == "No" || oldValue == "") && newValue == "Yes") {
676 loadClubFile(masterFile, clubList, true);
677 courseListModel->update(clubList);
683 void MainWindow::loadScoreFile(QString &fileName, QList<Score *> &list)
685 ScoreXmlHandler handler(list);
687 if (handler.parse(fileName))
688 qDebug() << "File loaded:" << fileName << " entries:" << list.size();
691 void MainWindow::saveScoreFile(QString &fileName, QList<Score *> &list)
693 ScoreXmlHandler handler(list);
695 if (handler.save(fileName))
697 qDebug() << "File saved:" << fileName << " entries:" << list.size();
699 qWarning() << "Unable to save:" << fileName;
702 void MainWindow::loadClubFile(QString &fileName, QList<Club *> &list, bool readOnly)
704 ClubXmlHandler handler(list);
706 if (handler.parse(fileName, readOnly))
707 qDebug() << "File loaded:" << fileName << " entries:" << list.size();
710 void MainWindow::saveClubFile(QString &fileName, QList<Club *> &list)
712 ClubXmlHandler handler(list);
714 if (handler.save(fileName))
716 qDebug() << "File saved:" << fileName << " entries:" << list.size();
718 qWarning() << "Unable to save:" << fileName;