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