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 qDebug() << score << course;
390 scoreWindow->setup(score, course);
394 void MainWindow::newScore()
397 SelectDialog *selectDialog = new SelectDialog(this);
399 selectDialog->init(clubList);
401 int result = selectDialog->exec();
407 selectDialog->results(clubName, courseName, date);
409 ScoreDialog *scoreDialog = new ScoreDialog(this);
410 QString title = "New Score: " + courseName + ", " + date;
411 scoreDialog->setWindowTitle(title);
413 Club *club = findClub(clubName);
415 showNote(tr("Error: no such club"));
418 Course *course = club->getCourse(courseName);
420 showNote(tr("Error: no such course:"));
423 scoreDialog->init(course);
424 result = scoreDialog->exec();
426 QVector<QString> scores(18);
428 scoreDialog->results(scores);
429 Score *score = new Score(scores, clubName, courseName, date);
432 // Sort the scores based on dates
433 qSort(scoreList.begin(), scoreList.end(), dateMoreThan);
435 saveScoreFile(scoreFile, scoreList);
436 scoreListModel->update(scoreList);
442 void MainWindow::editScore()
446 Score *score = currentScore();
449 course = findCourse(score->getClubName(), score->getCourseName());
451 if (!course || !score) {
452 qDebug() << "No score/course to edit";
456 QString date = score->getDate();
458 ScoreDialog *scoreDialog = new ScoreDialog(this);
459 scoreDialog->init(course, score);
461 QString title = "Edit Score: " + course->getName() + ", " + date;
462 scoreDialog->setWindowTitle(title);
464 int result = scoreDialog->exec();
466 QVector<QString> scores(18);
468 scoreDialog->results(scores);
470 score->update(scores);
472 // Sort the scores based on dates
473 qSort(scoreList.begin(), scoreList.end(), dateMoreThan);
475 saveScoreFile(scoreFile, scoreList);
481 void MainWindow::deleteScore()
485 scoreWindow->close();
487 QModelIndex index = selectionModel->currentIndex();
488 if (!index.isValid()) {
489 qDebug() << "Invalid index";
493 scoreList.removeAt(index.row());
495 saveScoreFile(scoreFile, scoreList);
496 scoreListModel->update(scoreList);
500 void MainWindow::viewCourse(Course * course)
503 courseWindow->setup(course);
504 courseWindow->show();
507 void MainWindow::newCourse()
510 CourseSelectDialog *selectDialog = new CourseSelectDialog(this);
512 int result = selectDialog->exec();
518 selectDialog->results(clubName, courseName);
520 CourseDialog *courseDialog = new CourseDialog(this);
521 courseDialog->init();
522 QString title = "New Course: " + clubName + "," + courseName;
523 courseDialog->setWindowTitle(title);
525 int result = courseDialog->exec();
527 QVector<QString> par(18);
528 QVector<QString> hcp(18);
529 QVector<QString> len(18);
531 courseDialog->results(par, hcp, len);
534 Club *club = findClub(clubName);
536 course = club->getCourse(courseName);
538 showNote(tr("Club/course already in the database"));
542 course = new Course(courseName, par, hcp);
543 club->addCourse(course);
547 // New club and course
548 club = new Club(clubName);
549 course = new Course(courseName, par, hcp);
550 club->addCourse(course);
554 saveClubFile(clubFile, clubList);
555 courseListModel->update(clubList);
561 void MainWindow::editCourse()
564 Course *course = currentCourse();
567 showNote(tr("No course on edit"));
571 CourseDialog *courseDialog = new CourseDialog(this);
572 courseDialog->init(course);
574 QString title = "Edit Course: " + course->getName();
575 courseDialog->setWindowTitle(title);
577 int result = courseDialog->exec();
579 QVector<QString> par(18);
580 QVector<QString> hcp(18);
581 QVector<QString> len(18);
583 courseDialog->results(par, hcp, len);
585 course->update(par, hcp, len);
586 saveClubFile(clubFile, clubList);
592 void MainWindow::deleteCourse()
596 Course * course = currentCourse();
599 qDebug() << "Invalid course for deletion";
602 club = course->parent();
604 // Can not delete course if it has scores -- check
605 if (findScore(club->getName(), course->getName()) != 0) {
606 showNote(tr("Can not delete course, delete scores on the course first"));
611 courseWindow->close();
613 club->delCourse(course);
615 if (club->isEmpty()) {
616 int index = clubList.indexOf(club);
618 clubList.removeAt(index);
622 saveClubFile(clubFile, clubList);
623 courseListModel->update(clubList);
627 void MainWindow::viewStatistics()
630 QMainWindow *win = new QMainWindow(this);
631 QString title = "Statistics";
632 win->setWindowTitle(title);
634 win->setAttribute(Qt::WA_Maemo5StackedWindow);
637 StatModel *model = new StatModel(clubList, scoreList);
639 QTableView *table = new QTableView;
641 table->setSelectionMode(QAbstractItemView::NoSelection);
642 table->setStyleSheet(statStyleSheet);
643 table->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
644 table->verticalHeader()->setResizeMode(QHeaderView::Stretch);
645 table->verticalHeader()->setAutoFillBackground(true);
646 table->setModel(model);
648 QWidget *central = new QWidget(win);
649 win->setCentralWidget(central);
651 QTextEdit *textEdit = new QTextEdit;
653 textEdit->setReadOnly(true);
655 QVBoxLayout *infoLayout = new QVBoxLayout;
656 infoLayout->addWidget(table);
658 QHBoxLayout *mainLayout = new QHBoxLayout(central);
659 mainLayout->addLayout(infoLayout);
660 central->setLayout(mainLayout);
665 void MainWindow::viewSettings()
668 SettingsDialog *dlg = new SettingsDialog(this);
670 dlg->init(conf, clubList);
672 int result = dlg->exec();
674 QString oldValue = conf.defaultCourses.toString();
676 QString newValue = conf.defaultCourses.toString();
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);
694 void MainWindow::loadScoreFile(QString &fileName, QList<Score *> &list)
696 ScoreXmlHandler handler(list);
698 if (handler.parse(fileName))
699 qDebug() << "File loaded:" << fileName << " entries:" << list.size();
702 void MainWindow::saveScoreFile(QString &fileName, QList<Score *> &list)
704 ScoreXmlHandler handler(list);
706 if (handler.save(fileName))
708 qDebug() << "File saved:" << fileName << " entries:" << list.size();
710 qWarning() << "Unable to save:" << fileName;
713 void MainWindow::loadClubFile(QString &fileName, QList<Club *> &list, bool readOnly)
715 ClubXmlHandler handler(list);
717 if (handler.parse(fileName, readOnly))
718 qDebug() << "File loaded:" << fileName << " entries:" << list.size();
721 void MainWindow::saveClubFile(QString &fileName, QList<Club *> &list)
723 ClubXmlHandler handler(list);
725 if (handler.save(fileName))
727 qDebug() << "File saved:" << fileName << " entries:" << list.size();
729 qWarning() << "Unable to save:" << fileName;