Merge branch 'master' of /opt/src/sb1/qt/scorecard
[scorecard] / src / score-dialog.cpp
1 /*
2  * Copyright (C) 2009 Sakari Poussa
3  *
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.
7  */
8
9 #include <QtGui>
10 #include <QInputContext>
11 #ifdef Q_WS_MAEMO_5
12 #include <QMaemo5InformationBox>
13 #endif
14
15 #include "score-dialog.h"
16 #include "score-common.h"
17 #include "table-model.h"
18
19 ////////////////////////////////////////////////////////////////////////////////
20 // ScoreWindow based on QMainWindow
21 // Usage: view scorecard 
22 ////////////////////////////////////////////////////////////////////////////////
23 ScoreWindow::ScoreWindow(QWidget *parent) : QMainWindow(parent)
24 {
25 #ifdef Q_WS_MAEMO_5
26     setAttribute(Qt::WA_Maemo5StackedWindow);
27 #endif
28
29     QAction *editAction = new QAction(tr("Edit"), this);
30     connect(editAction, SIGNAL(triggered()), parent, SLOT(editScore()));
31     menuBar()->addAction(editAction);
32
33     QAction *delAction = new QAction(tr("Delete"), this);
34     connect(delAction, SIGNAL(triggered()), parent, SLOT(deleteScore()));
35     menuBar()->addAction(delAction);
36
37     model = new ScoreTableModel;
38     
39     QTableView * table = new QTableView;
40     table->showGrid();
41     table->setSelectionMode(QAbstractItemView::NoSelection);
42     table->setStyleSheet(defaultStyleSheet);
43     table->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
44     table->verticalHeader()->setResizeMode(QHeaderView::Stretch);
45     table->horizontalHeader()->hide();
46     table->setModel(model);
47     
48     QWidget *central = new QWidget(this);
49     setCentralWidget(central);
50     
51     QVBoxLayout *layout = new QVBoxLayout;
52     layout->addWidget(table);
53     
54     central->setLayout(layout);
55 }
56
57 ScoreWindow::~ScoreWindow()
58 {
59     TRACE;
60 }
61
62 void ScoreWindow::setup(Score *score, Course *course)
63 {
64     TRACE;
65     QString title = QString("%1, %2 - %3").arg(score->getClubName()).arg(score->getCourseName()).arg(score->getDate());
66     setWindowTitle(title);
67     model->set(score, course);
68 }
69
70 ////////////////////////////////////////////////////////////////////////////////
71 // SelectDialog based on QDialog
72 // Usage: select course and date for entering score
73 ////////////////////////////////////////////////////////////////////////////////
74 SelectDialog::SelectDialog(QWidget *parent) : QDialog(parent)
75 {
76     resize(800, 350);
77
78     QWidget *centralWidget = new QWidget(this);
79     createLayout(centralWidget);
80
81     setWindowTitle(tr("ScoreCard: Select Course and Date"));
82 }
83
84 void SelectDialog::createLayout(QWidget *parent)
85 {
86     listWidgetClub = new QListWidget(parent);
87     pushButtonNext = new QPushButton(tr("Next"));
88
89     connect(pushButtonNext, SIGNAL(clicked()), this, SLOT(next()));
90
91     QDialogButtonBox * buttonBox = new QDialogButtonBox(Qt::Vertical);
92     buttonBox->addButton(pushButtonNext, QDialogButtonBox::ActionRole);
93
94     leftLayout = new QVBoxLayout;
95     leftLayout->addWidget(listWidgetClub);
96
97 #ifdef Q_WS_MAEMO_5
98     dateButton = new QMaemo5ValueButton();
99     dateButton->setValueLayout(QMaemo5ValueButton::ValueUnderText);
100     dateButton->setPickSelector(new QMaemo5DatePickSelector());
101     dateButton->setText(QString::fromUtf8("Date"));
102     leftLayout->addWidget(dateButton);
103 #else
104     QDate today(QDate::currentDate());
105     lineEditDate = new QLineEdit;
106     lineEditDate->setText(today.toString("yyyy-MM-dd"));
107     date = new QDateEdit;
108     leftLayout->addWidget(date);
109     leftLayout->addWidget(lineEditDate);
110 #endif
111
112     rightLayout = new QVBoxLayout;
113     rightLayout->addStretch();
114     rightLayout->addWidget(buttonBox);
115
116     QHBoxLayout *mainLayout = new QHBoxLayout(parent);
117     mainLayout->addLayout(leftLayout);
118     mainLayout->addLayout(rightLayout);
119
120     setLayout(mainLayout);
121 }
122
123 void SelectDialog::init(QList<Club *> &list)
124 {
125     TRACE;
126     clubList = list;
127
128     QListIterator<Club *> i(clubList);
129     int index = 0;
130     bool markedFlag = false;
131
132     while (i.hasNext()) {
133         Club *club = i.next();
134
135         QList<Course *> courseList = club->getCourseList();
136
137         QListIterator<Course *> j(courseList);
138         while (j.hasNext()) {
139             Course *course = j.next();
140
141             QListWidgetItem *newItem = new QListWidgetItem;
142             
143             QString entry = club->getName() + ", " + course->getName();
144
145             newItem->setText(entry);
146             listWidgetClub->insertItem(index, newItem);
147
148             if (!markedFlag & club->isHomeClub()) {
149                 listWidgetClub->setCurrentRow(index);
150                 // Mark the 1st course of the home club the selection
151                 markedFlag = true;
152             }
153             index++;
154         }
155     }
156 }
157
158 void SelectDialog::results(QString &club, 
159                            QString &course, 
160                            QString &date)
161 {  
162     QListWidgetItem *current = listWidgetClub->currentItem();
163
164     if (current) {
165         QString tmp = current->text();
166
167         QStringList stringList = tmp.split(", ");
168         club = stringList[0];
169         course = stringList[1];
170 #ifdef Q_WS_MAEMO_5
171         QMaemo5DatePickSelector *sel = (QMaemo5DatePickSelector *)dateButton->pickSelector();
172         QDate d = sel->currentDate();
173         // TODO: change to QDate
174         date = d.toString(Qt::ISODate);
175 #else
176         date = lineEditDate->text();
177 #endif
178     }
179 }
180
181 bool SelectDialog::validate(void)
182 {
183     return true;
184 }
185
186 void SelectDialog::next(void)
187 {
188     if (validate())
189         done(1);
190     else {
191         qDebug() << "SelectDialog: invalid data, cancel or correct";
192     }
193 }
194
195 void SelectDialog::reject(void)
196 {
197     done(0);
198 }
199
200 ////////////////////////////////////////////////////////////////////////////////
201 // ScoreDialog based on QDialog
202 // Usage: edit scorecard data
203 ////////////////////////////////////////////////////////////////////////////////
204 ScoreDialog18::ScoreDialog18(QWidget *parent) : ScoreDialog(parent)
205 {
206     TRACE;
207     resize(800, 400);
208     QFont font;
209     font.setPointSize(fontSize);
210     setFont(font);
211
212     QWidget *centralWidget = new QWidget(this);
213
214     createTable();
215     createButton();
216     
217     createLayout(centralWidget);
218 }
219
220 ScoreDialog18::~ScoreDialog18()
221 {
222     //if (centralWidget)
223     //  delete centralWidget;
224     if (leftLayout)
225         delete leftLayout;
226     if (rightLayout)
227         delete rightLayout;
228     //if (mainLayout)
229     //  delete mainLayout;
230     if (table)
231         delete table;
232 }
233
234 void ScoreDialog18::createLayout(QWidget *parent)
235 {
236     TRACE;
237     leftLayout = new QVBoxLayout;
238     leftLayout->addWidget(table);
239
240     QDialogButtonBox * buttonBoxUp = new QDialogButtonBox(Qt::Vertical);
241     buttonBoxUp->addButton(pushButtonUp, QDialogButtonBox::ActionRole);
242     buttonBoxUp->addButton(pushButtonDown, QDialogButtonBox::ActionRole);
243     buttonBoxUp->addButton(pushButtonNext, QDialogButtonBox::ActionRole);
244
245     QDialogButtonBox * buttonBoxDown = new QDialogButtonBox(Qt::Vertical);
246     buttonBoxDown->addButton(pushButtonFinish, QDialogButtonBox::ActionRole);
247
248     rightLayout = new QVBoxLayout;
249     rightLayout->addWidget(buttonBoxUp);
250     rightLayout->addStretch();
251     rightLayout->addWidget(buttonBoxDown);
252
253     QHBoxLayout *mainLayout = new QHBoxLayout(parent);
254     mainLayout->addLayout(leftLayout);
255     mainLayout->addLayout(rightLayout);
256     setLayout(mainLayout);
257 }
258
259 void ScoreDialog18::createTable(QWidget *parent)
260 {
261     TRACE;
262     table = new QTableWidget(ROWS, COLS, parent);
263
264     table->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
265     table->verticalHeader()->setResizeMode(QHeaderView::Stretch);
266     table->horizontalHeader()->hide();
267
268     table->setStyleSheet(defaultStyleSheet);
269
270     QStringList headers;
271     headers << "" << "Par" << "HCP" << "Score" << "" << "Par" << "HCP" << "Score";
272     table->setVerticalHeaderLabels(headers);
273 }
274
275 void ScoreDialog18::createButton(QWidget *parent)
276 {
277     TRACE;
278     Q_UNUSED(parent);
279     pushButtonUp = new QPushButton(tr("+"));
280     connect(pushButtonUp, SIGNAL(clicked()), this, SLOT(up()));
281     
282     pushButtonDown = new QPushButton(tr("-"));
283     connect(pushButtonDown, SIGNAL(clicked()), this, SLOT(down()));
284   
285     pushButtonNext = new QPushButton(tr("Next"));
286     connect(pushButtonNext, SIGNAL(clicked()), this, SLOT(next()));
287
288     pushButtonFinish = new QPushButton(tr("Finish"));
289     connect(pushButtonFinish, SIGNAL(clicked()), this, SLOT(finish()));
290 }
291
292 void ScoreDialog18::init(Course *course, Score *score)
293 {
294     TRACE;
295     QTableWidgetItem *par, *hcp, *scoreItem, *holeNum;
296
297     for (int i = 0; i < 18; i++) {
298         par = new QTableWidgetItem(course->getPar(i));
299         hcp = new QTableWidgetItem(course->getHcp(i));
300         if (score)
301             scoreItem = new QTableWidgetItem(score->getScore(i));
302         else
303             scoreItem = new QTableWidgetItem("");
304         holeNum = new QTableWidgetItem(QString::number(i+1));
305
306         holeNum->setTextAlignment(Qt::AlignCenter);
307         holeNum->setFlags(Qt::NoItemFlags);
308         holeNum->setForeground(ScoreColor::holeBg());
309         
310         par->setTextAlignment(Qt::AlignCenter);
311         par->setFlags(Qt::NoItemFlags);
312
313         hcp->setTextAlignment(Qt::AlignCenter);
314         hcp->setFlags(Qt::NoItemFlags);
315         
316         scoreItem->setTextAlignment(Qt::AlignCenter);
317
318         if (i < 9) {
319             table->setItem(ROW_HOLE, i, holeNum);
320             table->setItem(ROW_PAR, i, par);
321             table->setItem(ROW_HCP, i, hcp);
322             table->setItem(ROW_SCORE, i, scoreItem);
323         }
324         else {
325             table->setItem(ROW_HOLE_2, i-9, holeNum);
326             table->setItem(ROW_PAR_2, i-9, par);
327             table->setItem(ROW_HCP_2, i-9, hcp);
328             table->setItem(ROW_SCORE_2, i-9, scoreItem);
329         }
330     }
331     // This - for some unknown reason - does not work ...
332     table->setInputMethodHints(Qt::ImhDigitsOnly);
333
334     // Set focus to 1st cell
335     table->setCurrentCell(ROW_SCORE, 0);
336     if (!score)
337         setDefaultScore(table);
338 }
339
340 // Set default score to par if not set
341 void ScoreDialog18::setDefaultScore(QTableWidget *table)
342 {
343     int row = table->currentRow();
344     int col = table->currentColumn();
345   
346     if (row == ROW_SCORE)
347         row = ROW_PAR;
348     else if (row == ROW_SCORE_2)
349         row = ROW_PAR_2;
350     else {
351         qDebug() << "ERROR: unknown row in default score";
352         return;
353     }
354     QTableWidgetItem *par = table->item(row, col);
355     QTableWidgetItem *score = table->item(row + 2, col);
356
357     if (par && score && score->text() == "") {
358         QVariant value(par->text());
359         score->setData(Qt::DisplayRole, value);
360     }
361 }
362
363 void ScoreDialog18::up(void)
364 {
365     QTableWidgetItem *item = table->currentItem();
366
367     if (!item) {
368         qWarning() << "ERROR: no current item";
369         return;
370     }
371
372     int i = (item->text()).toInt();
373     QVariant value(i+1);
374     item->setData(Qt::DisplayRole, value);
375 }
376
377 void ScoreDialog18::down(void)
378 {
379     QTableWidgetItem *item = table->currentItem();
380
381     if (!item)
382         return;
383
384     int i = (item->text()).toInt();
385     QVariant value(i-1);
386     item->setData(Qt::DisplayRole, value);
387 }
388
389 void ScoreDialog18::next(void)
390 {
391     if (table) {
392         QTableWidgetItem *item = table->currentItem();
393         moveToNextCell(item);
394         setDefaultScore(table);
395     }
396 }
397
398 void ScoreDialog18::moveToNextCell(QTableWidgetItem *item)
399 {
400     if (!item)
401         return;
402
403     QTableWidget *table = item->tableWidget();
404
405     if (!table)
406         return;
407
408     int row = table->currentRow();
409     int col = table->currentColumn();
410
411     if (col < (COLS-1)) {
412         col++;
413     }
414     else if (col == (COLS-1)) {
415         col = 0;
416         row = (row == ROW_SCORE_2) ? ROW_SCORE : ROW_SCORE_2;
417     }
418     table->setCurrentCell(row, col);
419 }
420
421 void ScoreDialog18::results(QVector<QString> &scores)
422 {
423     TRACE;
424     for (int i = 0; i < 9; i++) {
425         QTableWidgetItem *frontItem = table->item(ROW_SCORE, i);
426         QTableWidgetItem *backItem = table->item(ROW_SCORE_2, i);
427
428         if (frontItem)
429             scores[i] = frontItem->text();
430
431         if (backItem)
432             scores[i+9] = backItem->text();
433     }
434 }
435
436 bool ScoreDialog18::validate(void)
437 {
438     for (int i=0; i<9; i++) {
439         QTableWidgetItem *frontItem = table->item(ROW_SCORE, i);
440         QTableWidgetItem *backItem = table->item(ROW_SCORE_2, i);
441     
442         if (!frontItem || !backItem)
443             return false;
444     
445         QString str1 = frontItem->text();
446         QString str2 = backItem->text();
447     
448         if (str1.isEmpty() || str2.isEmpty())
449             return false;
450     }
451     return true;
452 }
453
454 void ScoreDialog18::finish(void)
455 {
456     if (validate())
457         done(1);
458     else {
459         showNote("Invalid data - cancel or correct");
460     }
461 }
462
463 void ScoreDialog18::reject(void)
464 {
465     done(0);
466 }
467
468 void ScoreDialog18::showNote(QString msg)
469 {
470 #ifdef Q_WS_MAEMO_5
471     QMaemo5InformationBox::information(this, 
472                                        msg,
473                                        QMaemo5InformationBox::DefaultTimeout);
474 #endif
475 }
476
477 ////////////////////////////////////////////////////////////////////////////////
478 // ScoreDialogSingle based on QDialog
479 // Usage: edit scorecard data for single hole
480 ////////////////////////////////////////////////////////////////////////////////
481 ScoreDialogSingle::ScoreDialogSingle(QWidget *parent) : ScoreDialog(parent)
482 {
483     TRACE;
484     resize(800, 400);
485     QFont font;
486     font.setPointSize(fontSize);
487     setFont(font);
488
489     QWidget *centralWidget = new QWidget(this);
490
491     createTable();
492     createButton();
493     
494     createLayout(centralWidget);
495 }
496
497 ScoreDialogSingle::~ScoreDialogSingle()
498 {
499     //if (centralWidget)
500     //  delete centralWidget;
501     if (leftLayout)
502         delete leftLayout;
503     if (rightLayout)
504         delete rightLayout;
505     //if (mainLayout)
506     //  delete mainLayout;
507     if (table)
508         delete table;
509 }
510
511 void ScoreDialogSingle::createLayout(QWidget *parent)
512 {
513     TRACE;
514     leftLayout = new QVBoxLayout;
515     leftLayout->addWidget(table);
516
517     QDialogButtonBox * buttonBoxUp = new QDialogButtonBox(Qt::Vertical);
518     buttonBoxUp->addButton(pushButtonUp, QDialogButtonBox::ActionRole);
519     buttonBoxUp->addButton(pushButtonDown, QDialogButtonBox::ActionRole);
520     buttonBoxUp->addButton(pushButtonNext, QDialogButtonBox::ActionRole);
521
522     QDialogButtonBox * buttonBoxDown = new QDialogButtonBox(Qt::Vertical);
523     buttonBoxDown->addButton(pushButtonFinish, QDialogButtonBox::ActionRole);
524
525     rightLayout = new QVBoxLayout;
526     rightLayout->addWidget(buttonBoxUp);
527     rightLayout->addStretch();
528     rightLayout->addWidget(buttonBoxDown);
529
530     QHBoxLayout *mainLayout = new QHBoxLayout(parent);
531     mainLayout->addLayout(leftLayout);
532     mainLayout->addLayout(rightLayout);
533     setLayout(mainLayout);
534 }
535
536 void ScoreDialogSingle::createTable(QWidget *parent)
537 {
538     TRACE;
539     table = new QTableWidget(ROWS, COLS, parent);
540     QFont font;
541     font.setPointSize(32);
542     table->setFont(font);
543
544     table->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
545     table->verticalHeader()->setResizeMode(QHeaderView::Stretch);
546     table->horizontalHeader()->hide();
547
548     table->setStyleSheet(defaultStyleSheet);
549
550     QStringList headers;
551     headers << "Hole" << "Par" << "HCP" << "Score" << "Putts" << "Fairway" << "Green";
552     table->setVerticalHeaderLabels(headers);
553 }
554
555 void ScoreDialogSingle::createButton(QWidget *parent)
556 {
557     TRACE;
558     Q_UNUSED(parent);
559     pushButtonUp = new QPushButton(tr("+"));
560     connect(pushButtonUp, SIGNAL(clicked()), this, SLOT(up()));
561     
562     pushButtonDown = new QPushButton(tr("-"));
563     connect(pushButtonDown, SIGNAL(clicked()), this, SLOT(down()));
564   
565     pushButtonNext = new QPushButton(tr("Next"));
566     connect(pushButtonNext, SIGNAL(clicked()), this, SLOT(next()));
567
568     pushButtonFinish = new QPushButton(tr("Finish"));
569     connect(pushButtonFinish, SIGNAL(clicked()), this, SLOT(finish()));
570 }
571
572 void ScoreDialogSingle::init(Course *course, Score *score)
573 {
574     TRACE;
575     QTableWidgetItem *holeNum, *par, *hcp, *scoreItem, *putts, *fairway, *green;
576
577     for (int i = 0; i < 3; i++) {
578         par = new QTableWidgetItem(course->getPar(i));
579         hcp = new QTableWidgetItem(course->getHcp(i));
580         
581         if (score)
582             scoreItem = new QTableWidgetItem(score->getScore(i));
583         else
584             scoreItem = new QTableWidgetItem("");
585
586         putts = new QTableWidgetItem("2");
587         fairway = new QTableWidgetItem("Yes");
588         green = new QTableWidgetItem("Yes");
589
590         holeNum = new QTableWidgetItem(QString::number(i+1));
591
592         holeNum->setTextAlignment(Qt::AlignCenter);
593         holeNum->setFlags(Qt::NoItemFlags);
594         holeNum->setForeground(ScoreColor::holeBg());
595         
596         par->setTextAlignment(Qt::AlignCenter);
597         par->setFlags(Qt::NoItemFlags);
598
599         hcp->setTextAlignment(Qt::AlignCenter);
600         hcp->setFlags(Qt::NoItemFlags);
601         
602         scoreItem->setTextAlignment(Qt::AlignCenter);
603         putts->setTextAlignment(Qt::AlignCenter);
604         fairway->setTextAlignment(Qt::AlignCenter);
605         green->setTextAlignment(Qt::AlignCenter);
606
607         table->setItem(ROW_HOLE, i, holeNum);
608         table->setItem(ROW_PAR, i, par);
609         table->setItem(ROW_HCP, i, hcp);
610         table->setItem(ROW_SCORE, i, scoreItem);
611         table->setItem(ROW_PUTTS, i, putts);
612         table->setItem(ROW_FAIRWAY, i, fairway);
613         table->setItem(ROW_GREEN, i, green);
614     }
615     // Set focus to 1st cell
616     table->setCurrentCell(ROW_SCORE, 0);
617     if (!score)
618         setDefaultScore(table);
619 }
620
621 // Set default score to par if not set
622 // TODO: merge the two methods since they are the same
623 void ScoreDialogSingle::setDefaultScore(QTableWidget *table)
624 {
625     int row = table->currentRow();
626     int col = table->currentColumn();
627   
628     if (row == ROW_SCORE)
629         row = ROW_PAR;
630     else {
631         qDebug() << "ERROR: unknown row in default score";
632         return;
633     }
634     QTableWidgetItem *par = table->item(row, col);
635     QTableWidgetItem *score = table->item(row + 2, col);
636
637     if (par && score && score->text() == "") {
638         QVariant value(par->text());
639         score->setData(Qt::DisplayRole, value);
640     }
641 }
642
643 void ScoreDialogSingle::up(void)
644 {
645     QTableWidgetItem *item = table->currentItem();
646
647     if (!item) {
648         qWarning() << "ERROR: no current item";
649         return;
650     }
651
652     int i = (item->text()).toInt();
653     QVariant value(i+1);
654     item->setData(Qt::DisplayRole, value);
655 }
656
657 void ScoreDialogSingle::down(void)
658 {
659     QTableWidgetItem *item = table->currentItem();
660
661     if (!item)
662         return;
663
664     int i = (item->text()).toInt();
665     QVariant value(i-1);
666     item->setData(Qt::DisplayRole, value);
667 }
668
669 void ScoreDialogSingle::next(void)
670 {
671     if (table) {
672         QTableWidgetItem *item = table->currentItem();
673         moveToNextCell(item);
674         setDefaultScore(table);
675     }
676 }
677
678 void ScoreDialogSingle::moveToNextCell(QTableWidgetItem *item)
679 {
680     if (!item)
681         return;
682
683     QTableWidget *table = item->tableWidget();
684
685     if (!table)
686         return;
687
688     int row = table->currentRow();
689     int col = table->currentColumn();
690
691     qDebug() << row << col;
692     if (row < (ROWS - 1)) {
693         row++;
694     }
695     else if (row == (ROWS - 1)) {
696         row = ROW_SCORE;
697         col = (col == COLS-1) ? 0 : col + 1;
698     }
699     qDebug() << row << col;
700     table->setCurrentCell(row, col);
701 }
702
703 void ScoreDialogSingle::results(QVector<QString> &scores)
704 {
705     TRACE;
706 }