2 * Copyright (C) 2010 Charles Clement <caratorn _at_ gmail.com>
4 * This file is part of qquiz.
6 * qquiz is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 question::question(QString h, QString r) : hint(h), answer(r), answered(0) {
28 question::~question() {
32 quiz::quiz() : current(NULL), correct(0) {
35 window = new QWidget();
36 window->setWindowTitle(QApplication::translate("Qtquiz", "Qtquiz"));
38 menu = new QMenuBar(window);
39 choose = new QAction("Open", window);
40 QObject::connect(choose, SIGNAL(triggered()), this, SLOT(choose_quiz()));
42 menu->addAction(choose);
50 void quiz::retrieve_quizzes() {
56 QString datadir(PKGDATADIR);
59 list = dir.entryInfoList(QDir::Files);
61 cerr << "Can't find directory " << datadir.toStdString() << endl;
63 path.append(dir.homePath());
65 path.append(APP_NAME);
67 list.append(dir.entryInfoList(QDir::Files));
69 cerr << "Can't find directory " << path.toStdString() << endl;
71 for (int i = 0; i < list.size(); ++i) {
74 QFileInfo fileInfo = list.at(i);
75 q->path = fileInfo.absoluteFilePath();
76 QFile file(fileInfo.absoluteFilePath());
77 file.open(QFile::ReadOnly);
78 QTextStream stream(&file);
80 buf = stream.readLine();
81 } while (buf[0] == '#');
88 void quiz::choose_quiz() {
90 vector<quiz_file *>::iterator itr;
93 for (itr = files.begin(); itr != files.end() ; itr++) {
94 items << (*itr)->title;
97 //QString item = QInputDialog::getItem(window, tr("Choose quiz"),
98 // tr("Available quizzes:"), items, 0, false, &ok, QInputDialog::UseListViewForComboBoxItems);
99 QString item = QInputDialog::getItem(window, tr("Choose quiz"),
100 tr("Available quizzes:"), items, 0, false, &ok);
102 if (ok && !item.isEmpty()) {
104 vector<question *>::iterator itrq;
107 for ( itrq = questions.begin() ; itrq != questions.end() ; itrq++) {
108 (*itrq)->label->hide();
109 grid->removeWidget((*itrq)->label);
117 current = files.at(items.indexOf(item));
118 if(read_quiz(current->path.absolutePath().toStdString().c_str())) {
119 menu->addAction(give_up);
123 current_time = total_time;
124 timer = new QTimer(this);
125 connect(timer, SIGNAL(timeout()), this, SLOT(update_timer()));
133 int quiz::read_quiz(const char *filename) {
134 string parse_line, hint, answer;
136 string::size_type loc, mloc;
139 ifstream ifs (filename);
140 max_label_length = 0;
145 cerr << "Failed to open file " << filename << endl;
149 getline(ifs, buffer);
150 } while (buffer[0] == '#');
151 title = QString::fromStdString(buffer);
153 getline(ifs, buffer);
154 } while (buffer[0] == '#');
155 total_time = atoi(buffer.c_str());
156 /* convert minutes to seconds */
158 while (getline(ifs, parse_line)){
159 if (parse_line[0] == '#')
162 loc = parse_line.find(CHAR_DELIM);
163 if (loc == string::npos) {
164 cerr << "Wrong format in file " << filename << endl;
168 hint = parse_line.substr(0, loc);
169 if (hint.length() > max_label_length)
170 max_label_length = hint.length();
171 parse_line = parse_line.substr(loc);
172 mloc = parse_line.find(ANSWER_DELIM);
174 if (mloc == string::npos) {
175 answer = parse_line.substr(1);
177 answer = parse_line.substr(1, mloc - 1);
179 if (answer.length() > max_label_length )
180 max_label_length = answer.length();
181 qanswer = QString::fromStdString(answer);
182 qanswer = qanswer.trimmed();
183 q = new question(QString::fromStdString(hint), qanswer );
184 questions.push_back(q);
185 index[qanswer.toLower()] = i;
187 while (mloc != string::npos) {
188 parse_line = parse_line.substr(mloc + 1);
189 mloc = parse_line.find(ANSWER_DELIM);
190 if (mloc != string::npos) {
191 answer = parse_line.substr(0, mloc);
193 answer = parse_line.substr(0);
195 qanswer = QString::fromStdString(answer);
196 qanswer = qanswer.trimmed();
197 index[qanswer.toLower()] = i;
198 mloc = parse_line.find(ANSWER_DELIM);
208 void quiz::init_gui() {
209 QHBoxLayout *menu_layout;
211 line = new QLineEdit(window);
212 score = new QLabel("", window);
213 timer_label = new QLabel("0:00", window);
215 /* Disable auto-completion
217 //line->setCompleter((QCompleter *)0);
218 //line->setCompleter(0);
220 #if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)
221 // supposed to work in Qt 4.6
222 line->setInputMethodHints(Qt::ImhNoPredictiveText);
225 //line->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
226 line->setMinimumWidth(window->width() / 2);
227 score->setAlignment(Qt::AlignHCenter);
228 timer_label->setAlignment(Qt::AlignHCenter);
230 layout = new QVBoxLayout();
231 menu_layout = new QHBoxLayout();
233 score->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
234 line->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
235 timer_label->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
237 menu_layout->addWidget(score);
238 menu_layout->addWidget(line);
239 menu_layout->addWidget(timer_label);
241 menu_layout->setSizeConstraint(QLayout::SetFixedSize);
242 layout->addLayout(menu_layout);
244 scrollArea = new QScrollArea();
245 sub_window = new QWidget(scrollArea);
246 grid = new QGridLayout();
248 sub_window->setLayout(grid);
249 scrollArea->setWidget(sub_window);
251 scrollArea->setWidgetResizable(true);
252 scrollArea->setProperty("FingerScrollable", true);
253 scrollArea->setFocusPolicy(Qt::NoFocus);
255 layout->addWidget(scrollArea);
256 window->setLayout(layout);
258 QObject::connect(line, SIGNAL(textChanged(const QString&)), this, SLOT(buzz(const QString&)));
260 give_up = new QAction("Give up", window);
261 QObject::connect(give_up, SIGNAL(triggered()), this, SLOT(end()));
264 void quiz::buzz(const QString& buffer) {
265 map <QString, int>::iterator itr;
268 itr = index.find(buffer.toLower());
269 if (itr != index.end()) {
270 q = questions.at(itr->second);
275 q->label->setStyleSheet("QLabel { color: green }");
276 q->label->setText(q->answer);
281 if (correct == total) {
293 void quiz::display_score() {
294 QString score_text, ext;
296 score_text.setNum(correct);
297 score_text.append('/');
299 score_text.append(ext);
301 score->setText(score_text);
304 void quiz::display_grid() {
305 vector<question *>::iterator itrq;
306 int i,j, nr_columns, nr_col_padding;
312 QFontMetrics qfm = QFontMetrics(font);
313 example.append(max_label_length + 2, 'C');
314 pixelsWide = qfm.width(QString::fromStdString(example));
317 nr_columns = window->width() / pixelsWide;
318 nr_col_padding = (window->width() -
319 (2 * padding + nr_columns * 2 * padding) ) / pixelsWide;
320 nr_columns = nr_col_padding;
323 nr_columns = DEFAULT_NR_COL;
326 itrq = questions.begin();
327 for ( i = 0; itrq != questions.end() ; i++) {
329 for ( j = 0 ; j < nr_columns && itrq != questions.end() ; j++) {
330 (*itrq)->label = new QLabel((*itrq)->hint);
331 // Doesn't do anything on maemo
332 //(*itrq)->label->setFrameStyle(QFrame::Panel | QFrame::Raised);
334 grid->addWidget((*itrq)->label, i, j);
341 void quiz::update_timer() {
344 QTime t(0, current_time / 60, current_time % 60);
345 timer_label->setText(t.toString("m:ss"));
346 if (current_time == 0) {
352 vector<question *>::iterator itrq;
359 menu->removeAction(give_up);
360 for ( itrq = questions.begin() ; itrq != questions.end() ; itrq++) {
361 if (!(*itrq)->answered) {
362 (*itrq)->label->setStyleSheet("QLabel { color: red }");
363 (*itrq)->label->setText((*itrq)->answer);