1 /*
2 SPDX-FileCopyrightText: 2003-2010 Peter Hedlund <peter.hedlund@kdemail.net>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7 #include "qaview.h"
8
9 #include <QDBusInterface>
10 #include <QUrl>
11
12 #include <KLocalizedString>
13 #include <KNotification>
14
15 #include "prefs.h"
16 #include "kwqquizmodel.h"
17 #include "kwqscorewidget.h"
18
highlightError(const QString & c,const QString & e)19 QString highlightError(const QString & c, const QString & e)
20 {
21 if (c == e)
22 return c;
23
24 QString s = c;
25 if (s.left(4) == QLatin1String("<qt>") && e.left(4) != QLatin1String("<qt>"))
26 s = s.mid(4, s.length() - 9);
27
28 if (s == e)
29 return s;
30
31 QString result = QStringLiteral("<qt>");
32 int i = 0;
33 while (i < e.length() && s[i] == e[i])
34 result.append(e[i++]);
35 result.append("<b>");
36 QString result2 = QStringLiteral("</qt>");
37 int j = s.length() - 1;
38 int k = e.length() - 1;
39 while (j >= 0 && k >= 0 && s[j] == e[k])
40 {
41 result2.prepend(e[k]);
42 j--;
43 k--;
44 }
45 result2.prepend("</b>");
46
47 for (int m = i; m <= k; m++)
48 result.append(e[m]);
49
50 result.append(result2);
51 return result;
52 }
53
QAView(QWidget * parent,KActionCollection * actionCollection)54 QAView::QAView(QWidget *parent, KActionCollection * actionCollection) : KWQQuizView(parent, actionCollection)
55 {
56 setupUi(this);
57
58 connect(txtAnswer, SIGNAL(returnPressed()), this, SLOT(slotCheck()));
59 }
60
init()61 void QAView::init()
62 {
63 score->clear();
64 score->setQuestionCount(m_quiz->questionCount());
65 score->setAsPercent(Prefs::percent());
66
67 m_hintUsed = false;
68
69 QFont f = Prefs::editorFont();
70 f.setWeight(QFont::Normal);
71 lblQuestion->setFont(f);
72 lblAnswerBlank->setFont(f);
73 txtAnswer->setFont(f);
74 lblPreviousQuestion->setFont(f);
75 lblYourAnswer->setFont(f);
76 lblCorrect->setFont(f);
77
78 lblPreviousQuestionHeader->clear();
79 lblPreviousQuestion->clear();
80 lblYourAnswerHeader->clear();
81 lblYourAnswer->clear();
82 lblCorrectHeader->clear();
83 lblCorrect->clear();
84
85 picPrevious->clear();
86 picYourAnswer->clear();
87 picCorrectAnswer->clear();
88
89 m_actionCollection->action(QStringLiteral("quiz_check"))->setEnabled(true);
90 m_actionCollection->action(QStringLiteral("qa_mark_last_correct"))->setEnabled(false);
91 m_actionCollection->action(QStringLiteral("qa_hint"))->setEnabled(true);
92 m_actionCollection->action(QStringLiteral("quiz_repeat_errors"))->setEnabled(false);
93 m_actionCollection->action(QStringLiteral("quiz_export_errors"))->setEnabled(false);
94 m_actionCollection->action(QStringLiteral("quiz_audio_play"))->setEnabled(false);
95
96 // reset last file
97 audioPlayFile(QUrl(), true);
98
99 showQuestion();
100 txtAnswer->show();
101 txtAnswer->setFocus();
102 }
103
slotCheck()104 void QAView::slotCheck()
105 {
106 if (m_actionCollection->action(QStringLiteral("quiz_check"))->isEnabled())
107 {
108 bool fIsCorrect;
109
110 if (m_hintUsed && Prefs::hintError())
111 {
112 //Force an Error
113 fIsCorrect = m_quiz->checkAnswer(QLatin1String(""));
114 }
115 else
116 {
117 //Really check the answer
118 fIsCorrect = m_quiz->checkAnswer(txtAnswer->text());
119 }
120 //Reset for next question
121 m_hintUsed = false;
122
123 if (fIsCorrect)
124 {
125 picYourAnswer->setPixmap(QIcon::fromTheme(QStringLiteral("answer-correct")).pixmap(32));
126 lblYourAnswer->setText(m_quiz->yourAnswer(txtAnswer->text()));
127 lblCorrectHeader->clear();
128 picCorrectAnswer->clear();
129 lblCorrect->clear();
130 score->countIncrement(KWQScoreWidget::cdCorrect);
131 KNotification::event(QStringLiteral("QuizCorrect"), i18n("Your answer was correct!"));
132 m_actionCollection->action(QStringLiteral("qa_mark_last_correct"))->setEnabled(false);
133 }
134 else
135 {
136 picYourAnswer->setPixmap(QIcon::fromTheme(QStringLiteral("error")).pixmap(32));
137 lblYourAnswer->setText(highlightError(m_quiz->answer(), m_quiz->yourAnswer(txtAnswer->text())));
138 lblCorrect->setText(m_quiz->answer());
139 picCorrectAnswer->setPixmap(QIcon::fromTheme(QStringLiteral("answer-correct")).pixmap(32));
140 lblCorrectHeader->setText(i18n("Correct Answer"));
141 score->countIncrement(KWQScoreWidget::cdError);
142 KNotification::event(QStringLiteral("QuizError"), i18n("Your answer was incorrect."));
143 m_actionCollection->action(QStringLiteral("qa_mark_last_correct"))->setEnabled(true);
144 }
145
146 audioPlayAnswer();
147
148 lblPreviousQuestionHeader->setText(i18n("Previous Question"));
149 lblPreviousQuestion->setText(m_quiz->question());
150 //lblPreviousQuestion->setFont(m_quiz->fontQuestion(m_question));
151 picPrevious->setPixmap(QIcon::fromTheme(QStringLiteral("question")).pixmap(32));
152
153 lblYourAnswerHeader->setText(i18n("Your Answer"));
154
155 m_quiz->toNext();
156 if (!m_quiz->atEnd())
157 {
158 showQuestion();
159 }
160 else
161 {
162 m_quiz->finish();
163 m_actionCollection->action(QStringLiteral("quiz_check"))->setEnabled(false);
164 m_actionCollection->action(QStringLiteral("qa_hint"))->setEnabled(false);
165 m_actionCollection->action(QStringLiteral("quiz_repeat_errors"))->setEnabled(m_quiz->hasErrors());
166 m_actionCollection->action(QStringLiteral("quiz_export_errors"))->setEnabled(m_quiz->hasErrors());
167 m_actionCollection->action(QStringLiteral("qa_mark_last_correct"))->setEnabled(false);
168
169 lblQuestionLanguage->setText(i18n("Summary"));
170 lblQuestion->clear();
171 lblAnswerLanguage->clear();
172 lblAnswerBlank->hide();
173 txtAnswer->hide();
174 picQuestion->setPixmap(QIcon::fromTheme(QStringLiteral("kwordquiz")).pixmap(32));
175 picAnswer->clear();
176 }
177 }
178 }
179
slotHint()180 void QAView::slotHint()
181 {
182 QString answer = txtAnswer->text();
183 QString correctAnswer = m_quiz->hint();
184 if (correctAnswer.left(4) == QLatin1String("<qt>"))
185 {
186 correctAnswer = correctAnswer.remove(QStringLiteral("<qt>"));
187 correctAnswer = correctAnswer.remove(QStringLiteral("</qt>"));
188 }
189 int minLength = qMin(answer.length(), correctAnswer.length());
190
191 int correctCharCount = 1;
192
193 if (answer.length() > 0)
194 {
195 for(int i = 0; i < minLength; i++)
196 {
197 if (answer.at(i) == correctAnswer.at(i))
198 correctCharCount++;
199 }
200 }
201
202 txtAnswer->setText(correctAnswer.left(correctCharCount));
203 txtAnswer->setFocus();
204 txtAnswer->setCursorPosition(txtAnswer->text().length());
205
206 m_hintUsed = true;
207 }
208
209 /*!
210 \fn QAView::showQuestion(int i)
211 */
showQuestion()212 void QAView::showQuestion()
213 {
214 lblQuestionLanguage->setText(m_quiz ->langQuestion());
215 lblQuestion->setText(m_quiz ->question());
216 //audioPlayQuestion();
217
218 picQuestion->setPixmap(QIcon::fromTheme(m_quiz->quizIcon(KWQQuizModel::IconLeftCol)).pixmap(32));
219
220 lblAnswerLanguage->setText(m_quiz ->langAnswer());
221
222 if (!QString(m_quiz->blankAnswer()).isEmpty())
223 {
224 lblAnswerBlank->show();
225 lblAnswerBlank->setText(m_quiz->blankAnswer());
226 }
227 else
228 lblAnswerBlank->hide();
229
230 txtAnswer->setText(QLatin1String(""));
231
232 picAnswer->setPixmap(QIcon::fromTheme(m_quiz->quizIcon(KWQQuizModel::IconRightCol)).pixmap(32));
233
234 QString layout = m_quiz->kbAnswer();
235 if (!layout.isEmpty()) {
236 QDBusInterface kxkb(QStringLiteral("org.kde.keyboard"), QStringLiteral("/Layouts"), QStringLiteral("org.kde.KeyboardLayouts"));
237 if (kxkb.isValid())
238 kxkb.call(QStringLiteral("setLayout"), layout);
239 }
240 }
241
slotApplySettings()242 void QAView::slotApplySettings( )
243 {
244 score->setAsPercent(Prefs::percent());
245 }
246
slotSpecChar(const QChar & c)247 void QAView::slotSpecChar( const QChar & c)
248 {
249 if (txtAnswer->hasFocus())
250 {
251 if (txtAnswer->hasSelectedText())
252 {
253 QString ls = txtAnswer->text();
254 QString s = txtAnswer->selectedText();
255 int len = s.length();
256 int ss = txtAnswer->selectionStart();
257 ls = ls.replace(ss, len, c);
258 txtAnswer->setText(ls);
259 txtAnswer->setSelection(ss, 1);
260 }
261 else
262 {
263 QString s = txtAnswer->text();
264 int i = txtAnswer->cursorPosition();
265 s.insert(i, c);
266 txtAnswer->setText(s);
267 txtAnswer->setCursorPosition(i + 1);
268 }
269 }
270 }
271
slotMarkLastCorrect()272 void QAView::slotMarkLastCorrect( )
273 {
274 m_quiz->removeLastError();
275 score->swapCount();
276 m_actionCollection->action(QStringLiteral("qa_mark_last_correct"))->setEnabled(false);
277 }
278