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");
38 bool dateLessThan(const Score *s1, const Score *s2)
43 bool dateMoreThan(const Score *s1, const Score *s2)
47 // Find score based on club and course name
48 Score *MainWindow::findScore(QString & clubName, QString & courseName)
51 QListIterator<Score *> i(scoreList);
56 if ((s->getClubName() == clubName) &&
57 (s->getCourseName() == courseName))
63 // Find club based on name
64 Club *MainWindow::findClub(QString &name)
67 QListIterator<Club *> i(clubList);
72 if (c->getName() == name)
78 // Find course based on club & course name
79 Course *MainWindow::findCourse(const QString &clubName,
80 const QString &courseName)
83 QListIterator<Club *> i(clubList);
88 if (c->getName() == clubName) {
89 return c->getCourse(courseName);
95 // Find course based on current selection on the list
96 // TODO: make sure this is only called when course list is the model...
97 Course *MainWindow::currentCourse()
100 QModelIndex index = selectionModel->currentIndex();
102 if (!index.isValid())
105 const QAbstractItemModel *model = selectionModel->model();
106 QString str = model->data(index, Qt::DisplayRole).toString();
108 QStringList strList = str.split(", ");
109 if (strList.count() != 2) {
110 showNote(tr("Invalid course selection"));
113 return findCourse(strList[0], strList[1]);
116 // Find score based on current selection on the list
117 // TODO: make sure this is only called when score list is the model...
118 Score *MainWindow::currentScore()
121 QModelIndex index = selectionModel->currentIndex();
123 if (!index.isValid())
126 return scoreList.at(index.row());
129 void MainWindow::flushReadOnlyItems()
132 QMutableListIterator<Club *> i(clubList);
135 while (i.hasNext()) {
137 if (c->isReadOnly()) {
138 qDebug() << "Del:" << c->getName();
144 void MainWindow::markHomeClub()
147 QListIterator<Club *> i(clubList);
150 while (i.hasNext()) {
152 if (c->getName() == conf.homeClub)
153 c->setHomeClub(true);
155 c->setHomeClub(false);
159 MainWindow::MainWindow(QMainWindow *parent): QMainWindow(parent)
164 setAttribute(Qt::WA_Maemo5StackedWindow);
169 centralWidget = new QWidget(this);
171 setCentralWidget(centralWidget);
173 loadScoreFile(scoreFile, scoreList);
174 if (conf.defaultCourses == "Yes")
175 loadClubFile(masterFile, clubList, true);
176 loadClubFile(clubFile, clubList);
179 // Sort the scores based on dates
180 qSort(scoreList.begin(), scoreList.end(), dateMoreThan);
184 createListView(scoreList, clubList);
186 createLayoutList(centralWidget);
188 scoreWindow = new ScoreWindow(this);
189 courseWindow = new CourseWindow(this);
192 void MainWindow::loadSettings(void)
195 bool external = false;
201 // TODO: make via user option, automatic will never work
205 dataDir = "./" + dataDirName;
208 dataDir = mmcDir + "/" + appName + "/" + dataDirName;
211 dataDir = topDir + "/" + appName + "/" + dataDirName;
214 scoreFile = dataDir + "/" + scoreFileName;
215 clubFile = dataDir + "/" + clubFileName;
216 masterFile = dataDir + "/" + masterFileName;
220 if (!dir.mkpath(dataDir)) {
221 qWarning() << "Unable to create: " + dataDir;
224 qDebug() << "Data is at:" + dataDir;
226 settings.beginGroup(settingsGroup);
227 conf.hcp = settings.value(settingsHcp);
228 conf.homeClub = settings.value(settingsHomeClub);
229 conf.defaultCourses = settings.value(settingsDefaultCourses);
232 // Use default courses if no settings for that
233 if (!conf.defaultCourses.isValid())
234 conf.defaultCourses = "Yes";
236 qDebug() << "Settings: " << conf.hcp << conf.homeClub << conf.defaultCourses;
239 void MainWindow::saveSettings(void)
242 settings.beginGroup(settingsGroup);
243 if (conf.hcp.isValid())
244 settings.setValue(settingsHcp, conf.hcp);
245 if (conf.homeClub.isValid())
246 settings.setValue(settingsHomeClub, conf.homeClub);
247 if (conf.defaultCourses.isValid())
248 settings.setValue(settingsDefaultCourses, conf.defaultCourses);
252 void MainWindow::createLayoutList(QWidget *parent)
255 QVBoxLayout * tableLayout = new QVBoxLayout;
256 tableLayout->addWidget(list);
258 QHBoxLayout *mainLayout = new QHBoxLayout(parent);
259 mainLayout->addLayout(tableLayout);
260 parent->setLayout(mainLayout);
263 void MainWindow::createListView(QList<Score *> &scoreList,
264 QList <Club *> &clubList)
267 list = new QListView(this);
269 scoreListModel = new ScoreListModel(scoreList, clubList);
270 courseListModel = new CourseListModel(clubList);
272 list->setStyleSheet(defaultStyleSheet);
274 list->setSelectionMode(QAbstractItemView::SingleSelection);
275 list->setProperty("FingerScrolling", true);
280 connect(list, SIGNAL(clicked(QModelIndex)),
281 this, SLOT(clickedList(QModelIndex)));
284 void MainWindow::listScores()
287 list->setModel(scoreListModel);
288 selectionModel = list->selectionModel();
289 updateTitleBar(titleScores);
292 void MainWindow::listCourses()
295 list->setModel(courseListModel);
296 selectionModel = list->selectionModel();
297 updateTitleBar(titleCourses);
300 void MainWindow::createActions()
303 newScoreAction = new QAction(tr("New Score"), this);
304 connect(newScoreAction, SIGNAL(triggered()), this, SLOT(newScore()));
306 newCourseAction = new QAction(tr("New Course"), this);
307 connect(newCourseAction, SIGNAL(triggered()), this, SLOT(newCourse()));
309 statAction = new QAction(tr("Statistics"), this);
310 connect(statAction, SIGNAL(triggered()), this, SLOT(viewStatistics()));
312 settingsAction = new QAction(tr("Settings"), this);
313 connect(settingsAction, SIGNAL(triggered()), this, SLOT(viewSettings()));
315 // Maemo5 style menu filters
316 filterGroup = new QActionGroup(this);
317 filterGroup->setExclusive(true);
319 listScoreAction = new QAction(tr("Scores"), filterGroup);
320 listScoreAction->setCheckable(true);
321 listScoreAction->setChecked(true);
322 connect(listScoreAction, SIGNAL(triggered()), this, SLOT(listScores()));
324 listCourseAction = new QAction(tr("Courses"), filterGroup);
325 listCourseAction->setCheckable(true);
326 connect(listCourseAction, SIGNAL(triggered()), this, SLOT(listCourses()));
329 void MainWindow::createMenus()
333 menu = menuBar()->addMenu("");
335 menu = menuBar()->addMenu("Menu");
338 menu->addAction(newScoreAction);
339 menu->addAction(newCourseAction);
340 menu->addAction(statAction);
341 menu->addAction(settingsAction);
342 menu->addActions(filterGroup->actions());
345 void MainWindow::updateTitleBar(QString & msg)
351 void MainWindow::showNote(QString msg)
354 QMaemo5InformationBox::information(this,
356 QMaemo5InformationBox::DefaultTimeout);
360 void MainWindow::clickedList(const QModelIndex &index)
363 int row = index.row();
365 const QAbstractItemModel *m = index.model();
366 if (m == scoreListModel) {
367 if (row < scoreList.count()) {
368 Score * score = scoreList.at(row);
369 Course * course = findCourse(score->getClubName(), score->getCourseName());
370 viewScore(score, course);
373 else if (m == courseListModel) {
374 QString str = courseListModel->data(index, Qt::DisplayRole).toString();
375 QStringList strList = str.split(", ");
377 if (strList.count() != 2) {
378 showNote(QString("Invalid course selection"));
381 Course * course = findCourse(strList.at(0), strList.at(1));
386 void MainWindow::viewScore(Score * score, Course * course)
389 scoreWindow->setup(score, course);
393 void MainWindow::newScore()
396 SelectDialog *selectDialog = new SelectDialog(this);
398 selectDialog->init(clubList);
400 int result = selectDialog->exec();
406 selectDialog->results(clubName, courseName, date);
408 ScoreDialog *scoreDialog = new ScoreDialog(this);
409 QString title = "New Score: " + courseName + ", " + date;
410 scoreDialog->setWindowTitle(title);
412 Club *club = findClub(clubName);
414 showNote(tr("Error: no such club"));
417 Course *course = club->getCourse(courseName);
419 showNote(tr("Error: no such course:"));
422 scoreDialog->init(course);
423 result = scoreDialog->exec();
425 QVector<QString> scores(18);
427 scoreDialog->results(scores);
428 Score *score = new Score(scores, clubName, courseName, date);
431 // Sort the scores based on dates
432 qSort(scoreList.begin(), scoreList.end(), dateMoreThan);
434 saveScoreFile(scoreFile, scoreList);
435 scoreListModel->update(scoreList);
441 void MainWindow::editScore()
445 Score *score = currentScore();
448 course = findCourse(score->getClubName(), score->getCourseName());
450 if (!course || !score) {
451 qDebug() << "No score/course to edit";
455 QString date = score->getDate();
457 ScoreDialog *scoreDialog = new ScoreDialog(this);
458 scoreDialog->init(course, score);
460 QString title = "Edit Score: " + course->getName() + ", " + date;
461 scoreDialog->setWindowTitle(title);
463 int result = scoreDialog->exec();
465 QVector<QString> scores(18);
467 scoreDialog->results(scores);
469 score->update(scores);
471 // Sort the scores based on dates
472 qSort(scoreList.begin(), scoreList.end(), dateMoreThan);
474 saveScoreFile(scoreFile, scoreList);
480 void MainWindow::deleteScore()
484 scoreWindow->close();
486 QModelIndex index = selectionModel->currentIndex();
487 if (!index.isValid()) {
488 qDebug() << "Invalid index";
492 scoreList.removeAt(index.row());
494 saveScoreFile(scoreFile, scoreList);
495 scoreListModel->update(scoreList);
499 void MainWindow::viewCourse(Course * course)
502 courseWindow->setup(course);
503 courseWindow->show();
506 void MainWindow::newCourse()
509 CourseSelectDialog *selectDialog = new CourseSelectDialog(this);
511 int result = selectDialog->exec();
517 selectDialog->results(clubName, courseName);
519 CourseDialog *courseDialog = new CourseDialog(this);
520 courseDialog->init();
521 QString title = "New Course: " + clubName + "," + courseName;
522 courseDialog->setWindowTitle(title);
524 int result = courseDialog->exec();
526 QVector<QString> par(18);
527 QVector<QString> hcp(18);
528 QVector<QString> len(18);
530 courseDialog->results(par, hcp, len);
533 Club *club = findClub(clubName);
535 course = club->getCourse(courseName);
537 showNote(tr("Club/course already in the database"));
541 course = new Course(courseName, par, hcp);
542 club->addCourse(course);
546 // New club and course
547 club = new Club(clubName);
548 course = new Course(courseName, par, hcp);
549 club->addCourse(course);
553 saveClubFile(clubFile, clubList);
554 courseListModel->update(clubList);
560 void MainWindow::editCourse()
563 Course *course = currentCourse();
566 showNote(tr("No course on edit"));
570 CourseDialog *courseDialog = new CourseDialog(this);
571 courseDialog->init(course);
573 QString title = "Edit Course: " + course->getName();
574 courseDialog->setWindowTitle(title);
576 int result = courseDialog->exec();
578 QVector<QString> par(18);
579 QVector<QString> hcp(18);
580 QVector<QString> len(18);
582 courseDialog->results(par, hcp, len);
584 course->update(par, hcp, len);
585 saveClubFile(clubFile, clubList);
591 void MainWindow::deleteCourse()
595 Course * course = currentCourse();
598 qDebug() << "Invalid course for deletion";
601 club = course->parent();
603 // Can not delete course if it has scores -- check
604 if (findScore(club->getName(), course->getName()) != 0) {
605 showNote(tr("Can not delete course, delete scores on the course first"));
610 courseWindow->close();
612 club->delCourse(course);
614 if (club->isEmpty()) {
615 int index = clubList.indexOf(club);
617 clubList.removeAt(index);
621 saveClubFile(clubFile, clubList);
622 courseListModel->update(clubList);
626 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(statStyleSheet);
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()
667 SettingsDialog *dlg = new SettingsDialog(this);
669 dlg->init(conf, clubList);
671 int result = dlg->exec();
673 QString oldValue = conf.defaultCourses.toString();
675 QString newValue = conf.defaultCourses.toString();
678 // Reload club list, or drop r/o courses from list
679 if (oldValue == "Yes" && newValue == "No") {
680 flushReadOnlyItems();
681 courseListModel->update(clubList);
684 else if ((oldValue == "No" || oldValue == "") && newValue == "Yes") {
685 loadClubFile(masterFile, clubList, true);
686 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;