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)
48 bool scoreMoreThan(const Score *s1, const Score *s2)
50 return s1->getTotal(Total) > s2->getTotal(Total);
53 // Find score based on club and course name
54 Score *MainWindow::findScore(QString & clubName, QString & courseName)
57 QListIterator<Score *> i(scoreList);
62 if ((s->getClubName() == clubName) &&
63 (s->getCourseName() == courseName))
69 // Find club based on name
70 Club *MainWindow::findClub(QString &name)
73 QListIterator<Club *> i(clubList);
78 if (c->getName() == name)
84 // Find course based on club & course name
85 Course *MainWindow::findCourse(const QString &clubName,
86 const QString &courseName)
89 QListIterator<Club *> i(clubList);
94 if (c->getName() == clubName) {
95 return c->getCourse(courseName);
101 // Find course based on current selection on the list
102 // TODO: make sure this is only called when course list is the model...
103 Course *MainWindow::currentCourse()
106 QModelIndex index = selectionModel->currentIndex();
108 if (!index.isValid())
111 const QAbstractItemModel *model = selectionModel->model();
112 QString str = model->data(index, Qt::DisplayRole).toString();
114 QStringList strList = str.split(", ");
115 if (strList.count() != 2) {
116 showNote(tr("Invalid course selection"));
119 return findCourse(strList[0], strList[1]);
122 // Find score based on current selection on the list
123 // TODO: make sure this is only called when score list is the model...
124 Score *MainWindow::currentScore()
127 QModelIndex index = selectionModel->currentIndex();
129 if (!index.isValid())
132 return scoreList.at(index.row());
135 void MainWindow::flushReadOnlyItems()
138 QMutableListIterator<Club *> i(clubList);
141 while (i.hasNext()) {
143 if (c->isReadOnly()) {
144 qDebug() << "Del:" << c->getName();
150 void MainWindow::markHomeClub()
153 QListIterator<Club *> i(clubList);
156 while (i.hasNext()) {
158 if (c->getName() == conf.homeClub)
159 c->setHomeClub(true);
161 c->setHomeClub(false);
165 void MainWindow::sortScoreList()
167 if (conf.sortOrder == "Date")
168 qSort(scoreList.begin(), scoreList.end(), dateMoreThan);
169 else if (conf.sortOrder == "Score")
170 qSort(scoreList.begin(), scoreList.end(), scoreMoreThan);
173 MainWindow::MainWindow(QMainWindow *parent): QMainWindow(parent)
178 setAttribute(Qt::WA_Maemo5StackedWindow);
183 centralWidget = new QWidget(this);
185 setCentralWidget(centralWidget);
187 loadScoreFile(scoreFile, scoreList);
188 if (conf.defaultCourses == "Yes")
189 loadClubFile(masterFile, clubList, true);
190 loadClubFile(clubFile, clubList);
193 // Sort the scores based on settings
199 createListView(scoreList, clubList);
201 createLayoutList(centralWidget);
203 scoreWindow = new ScoreWindow(this);
204 courseWindow = new CourseWindow(this);
207 void MainWindow::loadSettings(void)
210 bool external = false;
216 // TODO: make via user option, automatic will never work
220 dataDir = "./" + dataDirName;
223 dataDir = mmcDir + "/" + appName + "/" + dataDirName;
226 dataDir = topDir + "/" + appName + "/" + dataDirName;
229 scoreFile = dataDir + "/" + scoreFileName;
230 clubFile = dataDir + "/" + clubFileName;
231 masterFile = dataDir + "/" + masterFileName;
235 if (!dir.mkpath(dataDir)) {
236 qWarning() << "Unable to create: " + dataDir;
239 qDebug() << "Data is at:" + dataDir;
241 settings.beginGroup(settingsGroup);
242 conf.hcp = settings.value(settingsHcp);
243 conf.homeClub = settings.value(settingsHomeClub);
244 conf.sortOrder = settings.value(settingsSortOrder);
245 conf.defaultCourses = settings.value(settingsDefaultCourses);
248 // Use default courses if no settings for that
249 if (!conf.defaultCourses.isValid())
250 conf.defaultCourses = "Yes";
252 // Use date sort order if no settings for that
253 if (!conf.sortOrder.isValid())
254 conf.sortOrder = "Yes";
256 qDebug() << "Settings: " << conf.hcp << conf.homeClub << conf.sortOrder << conf.defaultCourses;
259 void MainWindow::saveSettings(void)
262 settings.beginGroup(settingsGroup);
263 if (conf.hcp.isValid())
264 settings.setValue(settingsHcp, conf.hcp);
265 if (conf.homeClub.isValid())
266 settings.setValue(settingsHomeClub, conf.homeClub);
267 if (conf.sortOrder.isValid())
268 settings.setValue(settingsSortOrder, conf.sortOrder);
269 if (conf.defaultCourses.isValid())
270 settings.setValue(settingsDefaultCourses, conf.defaultCourses);
274 void MainWindow::createLayoutList(QWidget *parent)
277 QVBoxLayout * tableLayout = new QVBoxLayout;
278 tableLayout->addWidget(list);
280 QHBoxLayout *mainLayout = new QHBoxLayout(parent);
281 mainLayout->addLayout(tableLayout);
282 parent->setLayout(mainLayout);
285 void MainWindow::createListView(QList<Score *> &scoreList,
286 QList <Club *> &clubList)
289 list = new QListView(this);
291 scoreListModel = new ScoreListModel(scoreList, clubList);
292 courseListModel = new CourseListModel(clubList);
294 list->setStyleSheet(defaultStyleSheet);
296 list->setSelectionMode(QAbstractItemView::SingleSelection);
297 list->setProperty("FingerScrolling", true);
302 connect(list, SIGNAL(clicked(QModelIndex)),
303 this, SLOT(clickedList(QModelIndex)));
306 void MainWindow::listScores()
309 list->setModel(scoreListModel);
310 selectionModel = list->selectionModel();
311 updateTitleBar(titleScores);
314 void MainWindow::listCourses()
317 list->setModel(courseListModel);
318 selectionModel = list->selectionModel();
319 updateTitleBar(titleCourses);
322 void MainWindow::createActions()
325 newScoreAction = new QAction(tr("New Score"), this);
326 connect(newScoreAction, SIGNAL(triggered()), this, SLOT(newScore()));
328 newCourseAction = new QAction(tr("New Course"), this);
329 connect(newCourseAction, SIGNAL(triggered()), this, SLOT(newCourse()));
331 statAction = new QAction(tr("Statistics"), this);
332 connect(statAction, SIGNAL(triggered()), this, SLOT(viewStatistics()));
334 settingsAction = new QAction(tr("Settings"), this);
335 connect(settingsAction, SIGNAL(triggered()), this, SLOT(viewSettings()));
337 // Maemo5 style menu filters
338 filterGroup = new QActionGroup(this);
339 filterGroup->setExclusive(true);
341 listScoreAction = new QAction(tr("Scores"), filterGroup);
342 listScoreAction->setCheckable(true);
343 listScoreAction->setChecked(true);
344 connect(listScoreAction, SIGNAL(triggered()), this, SLOT(listScores()));
346 listCourseAction = new QAction(tr("Courses"), filterGroup);
347 listCourseAction->setCheckable(true);
348 connect(listCourseAction, SIGNAL(triggered()), this, SLOT(listCourses()));
351 void MainWindow::createMenus()
355 menu = menuBar()->addMenu("");
357 menu = menuBar()->addMenu("Menu");
360 menu->addAction(newScoreAction);
361 menu->addAction(newCourseAction);
362 menu->addAction(statAction);
363 menu->addAction(settingsAction);
364 menu->addActions(filterGroup->actions());
367 void MainWindow::updateTitleBar(QString & msg)
373 void MainWindow::showNote(QString msg)
376 QMaemo5InformationBox::information(this,
378 QMaemo5InformationBox::DefaultTimeout);
382 void MainWindow::clickedList(const QModelIndex &index)
385 int row = index.row();
387 const QAbstractItemModel *m = index.model();
388 if (m == scoreListModel) {
389 if (row < scoreList.count()) {
390 Score * score = scoreList.at(row);
391 Course * course = findCourse(score->getClubName(), score->getCourseName());
392 viewScore(score, course);
395 else if (m == courseListModel) {
396 QString str = courseListModel->data(index, Qt::DisplayRole).toString();
397 QStringList strList = str.split(", ");
399 if (strList.count() != 2) {
400 showNote(QString("Invalid course selection"));
403 Course * course = findCourse(strList.at(0), strList.at(1));
408 void MainWindow::viewScore(Score * score, Course * course)
411 scoreWindow->setup(score, course);
415 void MainWindow::newScore()
418 SelectDialog *selectDialog = new SelectDialog(this);
420 selectDialog->init(clubList);
422 int result = selectDialog->exec();
428 selectDialog->results(clubName, courseName, date);
430 ScoreDialog *scoreDialog = new ScoreDialog(this);
431 QString title = "New Score: " + courseName + ", " + date;
432 scoreDialog->setWindowTitle(title);
434 Club *club = findClub(clubName);
436 showNote(tr("Error: no such club"));
439 Course *course = club->getCourse(courseName);
441 showNote(tr("Error: no such course:"));
444 scoreDialog->init(course);
445 result = scoreDialog->exec();
447 QVector<QString> scores(18);
449 scoreDialog->results(scores);
450 Score *score = new Score(scores, clubName, courseName, date);
453 // Sort the scores based on settings
456 saveScoreFile(scoreFile, scoreList);
457 scoreListModel->update(scoreList);
463 void MainWindow::editScore()
467 Score *score = currentScore();
470 course = findCourse(score->getClubName(), score->getCourseName());
472 if (!course || !score) {
473 qDebug() << "No score/course to edit";
477 QString date = score->getDate();
479 ScoreDialog *scoreDialog = new ScoreDialog(this);
480 scoreDialog->init(course, score);
482 QString title = "Edit Score: " + course->getName() + ", " + date;
483 scoreDialog->setWindowTitle(title);
485 int result = scoreDialog->exec();
487 QVector<QString> scores(18);
489 scoreDialog->results(scores);
491 score->update(scores);
493 // Sort the scores based on dates
494 qSort(scoreList.begin(), scoreList.end(), dateMoreThan);
496 saveScoreFile(scoreFile, scoreList);
502 void MainWindow::deleteScore()
506 scoreWindow->close();
508 QModelIndex index = selectionModel->currentIndex();
509 if (!index.isValid()) {
510 qDebug() << "Invalid index";
514 scoreList.removeAt(index.row());
516 saveScoreFile(scoreFile, scoreList);
517 scoreListModel->update(scoreList);
521 void MainWindow::viewCourse(Course * course)
524 courseWindow->setup(course);
525 courseWindow->show();
528 void MainWindow::newCourse()
531 CourseSelectDialog *selectDialog = new CourseSelectDialog(this);
533 int result = selectDialog->exec();
539 selectDialog->results(clubName, courseName);
541 CourseDialog *courseDialog = new CourseDialog(this);
542 courseDialog->init();
543 QString title = "New Course: " + clubName + "," + courseName;
544 courseDialog->setWindowTitle(title);
546 int result = courseDialog->exec();
548 QVector<QString> par(18);
549 QVector<QString> hcp(18);
550 QVector<QString> len(18);
552 courseDialog->results(par, hcp, len);
555 Club *club = findClub(clubName);
557 course = club->getCourse(courseName);
559 showNote(tr("Club/course already in the database"));
563 course = new Course(courseName, par, hcp);
564 club->addCourse(course);
568 // New club and course
569 club = new Club(clubName);
570 course = new Course(courseName, par, hcp);
571 club->addCourse(course);
575 saveClubFile(clubFile, clubList);
576 courseListModel->update(clubList);
582 void MainWindow::editCourse()
585 Course *course = currentCourse();
588 showNote(tr("No course on edit"));
592 CourseDialog *courseDialog = new CourseDialog(this);
593 courseDialog->init(course);
595 QString title = "Edit Course: " + course->getName();
596 courseDialog->setWindowTitle(title);
598 int result = courseDialog->exec();
600 QVector<QString> par(18);
601 QVector<QString> hcp(18);
602 QVector<QString> len(18);
604 courseDialog->results(par, hcp, len);
606 course->update(par, hcp, len);
607 saveClubFile(clubFile, clubList);
613 void MainWindow::deleteCourse()
617 Course * course = currentCourse();
620 qDebug() << "Invalid course for deletion";
623 club = course->parent();
625 // Can not delete course if it has scores -- check
626 if (findScore(club->getName(), course->getName()) != 0) {
627 showNote(tr("Can not delete course, delete scores on the course first"));
632 courseWindow->close();
634 club->delCourse(course);
636 if (club->isEmpty()) {
637 int index = clubList.indexOf(club);
639 clubList.removeAt(index);
643 saveClubFile(clubFile, clubList);
644 courseListModel->update(clubList);
648 void MainWindow::viewStatistics()
651 QMainWindow *win = new QMainWindow(this);
652 QString title = "Statistics";
653 win->setWindowTitle(title);
655 win->setAttribute(Qt::WA_Maemo5StackedWindow);
658 StatModel *model = new StatModel(clubList, scoreList);
660 QTableView *table = new QTableView;
662 table->setSelectionMode(QAbstractItemView::NoSelection);
663 table->setStyleSheet(statStyleSheet);
664 table->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
665 table->verticalHeader()->setResizeMode(QHeaderView::Stretch);
666 table->verticalHeader()->setAutoFillBackground(true);
667 table->setModel(model);
669 QWidget *central = new QWidget(win);
670 win->setCentralWidget(central);
672 QTextEdit *textEdit = new QTextEdit;
674 textEdit->setReadOnly(true);
676 QVBoxLayout *infoLayout = new QVBoxLayout;
677 infoLayout->addWidget(table);
679 QHBoxLayout *mainLayout = new QHBoxLayout(central);
680 mainLayout->addLayout(infoLayout);
681 central->setLayout(mainLayout);
686 void MainWindow::viewSettings()
689 SettingsDialog *dlg = new SettingsDialog(this);
691 dlg->init(conf, clubList);
693 int result = dlg->exec();
695 QString oldValue = conf.defaultCourses.toString();
697 QString newValue = conf.defaultCourses.toString();
700 // Reload club list, or drop r/o courses from list
701 if (oldValue == "Yes" && newValue == "No") {
702 flushReadOnlyItems();
703 courseListModel->update(clubList);
706 else if ((oldValue == "No" || oldValue == "") && newValue == "Yes") {
707 loadClubFile(masterFile, clubList, true);
708 courseListModel->update(clubList);
711 // TODO: do these only if needed
714 scoreListModel->update(scoreList);
719 void MainWindow::loadScoreFile(QString &fileName, QList<Score *> &list)
721 ScoreXmlHandler handler(list);
723 if (handler.parse(fileName))
724 qDebug() << "File loaded:" << fileName << " entries:" << list.size();
727 void MainWindow::saveScoreFile(QString &fileName, QList<Score *> &list)
729 ScoreXmlHandler handler(list);
731 if (handler.save(fileName))
733 qDebug() << "File saved:" << fileName << " entries:" << list.size();
735 qWarning() << "Unable to save:" << fileName;
738 void MainWindow::loadClubFile(QString &fileName, QList<Club *> &list, bool readOnly)
740 ClubXmlHandler handler(list);
742 if (handler.parse(fileName, readOnly))
743 qDebug() << "File loaded:" << fileName << " entries:" << list.size();
746 void MainWindow::saveClubFile(QString &fileName, QList<Club *> &list)
748 ClubXmlHandler handler(list);
750 if (handler.save(fileName))
752 qDebug() << "File saved:" << fileName << " entries:" << list.size();
754 qWarning() << "Unable to save:" << fileName;