31 #include "templates/flashcard/flashcardeditor.h"
33 #include "templates/flashcard/flashcardquestion.h"
34 #include "templates/flashcard/flashcardcore.h"
35 #include "templates/flashcard/flashcardentrypoint.h"
36 #include "miscellaneous/iconfactory.h"
37 #include "miscellaneous/iofactory.h"
38 #include "core/templatefactory.h"
41 #include <QFileDialog>
44 FlashCardEditor::FlashCardEditor(
TemplateCore *core, QWidget *parent)
49 QRegExpValidator *author_validator =
new QRegExpValidator(
this);
50 QRegExpValidator *title_validator =
new QRegExpValidator(
this);
52 author_validator->setRegExp(QRegExp(
".{,50}"));
53 title_validator->setRegExp(QRegExp(
".{,100}"));
55 m_ui->m_txtAuthor->lineEdit()->setValidator(author_validator);
56 m_ui->m_txtName->lineEdit()->setValidator(title_validator);
59 QRegExpValidator *question_validator =
new QRegExpValidator(
this);
60 QRegExpValidator *hint_validator =
new QRegExpValidator(
this);
62 question_validator->setRegExp(QRegExp(
".{,100}"));
63 hint_validator->setRegExp(QRegExp(
".{,30}"));
65 m_ui->m_txtQuestion->lineEdit()->setValidator(question_validator);
66 m_ui->m_txtHint->lineEdit()->setValidator(hint_validator);
69 QList<QWidget*> tab_order_widgets;
70 tab_order_widgets << m_ui->m_txtQuestion->lineEdit() << m_ui->m_btnPictureSelect <<
71 m_ui->m_txtAnswer->lineEdit() << m_ui->m_txtHint->lineEdit() <<
72 m_ui->m_txtAuthor->lineEdit() << m_ui->m_txtName->lineEdit() <<
73 m_ui->m_listQuestions << m_ui->m_btnQuestionAdd << m_ui->m_btnQuestionRemove <<
74 m_ui->m_btnQuestionUp << m_ui->m_btnQuestionDown;
76 for (
int i = 1; i < tab_order_widgets.size(); i++) {
77 setTabOrder(tab_order_widgets.at(i - 1), tab_order_widgets.at(i));
80 m_ui->m_txtNumberOfQuestions->lineEdit()->setEnabled(
false);
82 m_ui->m_lblPictureFile->label()->setWordWrap(
true);
83 m_ui->m_txtAnswer->lineEdit()->setPlaceholderText(tr(
"Answer for the answer"));
84 m_ui->m_txtHint->lineEdit()->setPlaceholderText(tr(
"Hint for the answer"));
86 m_ui->m_lblPictureFile->setStatus(WidgetWithStatus::Error, QString(), tr(
"No picture selected"));
87 m_ui->m_txtAuthor->lineEdit()->setPlaceholderText(tr(
"Author of this quiz"));
88 m_ui->m_txtName->lineEdit()->setPlaceholderText(tr(
"Name of this quiz"));
92 m_ui->m_btnQuestionAdd->setIcon(factory->
fromTheme(
"item-add"));
93 m_ui->m_btnQuestionRemove->setIcon(factory->
fromTheme(
"item-remove"));
94 m_ui->m_btnQuestionUp->setIcon(factory->
fromTheme(
"move-up"));
95 m_ui->m_btnQuestionDown->setIcon(factory->
fromTheme(
"move-down"));
97 connect(m_ui->m_btnPictureSelect, SIGNAL(clicked()),
this, SLOT(selectPicture()));
98 connect(m_ui->m_txtAuthor->lineEdit(), SIGNAL(textChanged(QString)),
this, SLOT(onAuthorChanged(QString)));
99 connect(m_ui->m_txtQuestion, SIGNAL(textEdited(QString)),
this, SLOT(saveQuestion()));
100 connect(m_ui->m_txtName->lineEdit(), SIGNAL(textChanged(QString)),
this, SLOT(onNameChanged(QString)));
101 connect(m_ui->m_txtAnswer->lineEdit(), SIGNAL(textEdited(QString)),
this, SLOT(onAnswerChanged(QString)));
102 connect(m_ui->m_txtHint->lineEdit(), SIGNAL(textEdited(QString)),
this, SLOT(onHintChanged(QString)));
103 connect(m_ui->m_btnQuestionAdd, SIGNAL(clicked()),
this, SLOT(addQuestion()));
104 connect(m_ui->m_btnQuestionRemove, SIGNAL(clicked()),
this, SLOT(removeQuestion()));
105 connect(m_ui->m_listQuestions, SIGNAL(currentRowChanged(
int)),
this, SLOT(loadQuestion(
int)));
106 connect(m_ui->m_btnQuestionUp, SIGNAL(clicked()),
this, SLOT(moveQuestionUp()));
107 connect(m_ui->m_btnQuestionDown, SIGNAL(clicked()),
this, SLOT(moveQuestionDown()));
109 setEditorsEnabled(
false);
110 updateQuestionCount();
112 qRegisterMetaType<FlashCardQuestion>(
"FlashCardQuestion");
119 FlashCardEditor::~FlashCardEditor() {
120 qDebug(
"Destroying FlashCardEditor instance.");
125 void FlashCardEditor::updateQuestionCount() {
126 m_ui->m_txtNumberOfQuestions->lineEdit()->setText(QString::number(m_ui->m_listQuestions->count()));
128 if (m_ui->m_listQuestions->count() > 0) {
129 m_ui->m_txtNumberOfQuestions->setStatus(WidgetWithStatus::Ok, tr(
"Collection contains at least one question."));
132 m_ui->m_txtNumberOfQuestions->setStatus(WidgetWithStatus::Error, tr(
"Collection does not contain any questions."));
138 !m_ui->m_txtName->lineEdit()->text().simplified().isEmpty() &&
139 !m_ui->m_txtAuthor->lineEdit()->text().simplified().isEmpty() &&
140 !activeQuestions().isEmpty();
148 QDomDocument source_document = qApp->templateManager()->generateBundleHeader(
core()->entryPoint()->typeIndentifier(),
149 m_ui->m_txtAuthor->lineEdit()->text(),
151 m_ui->m_txtName->lineEdit()->text(),
154 FIND_DATA_ELEMENT(data_element, source_document);
157 QDomElement item_element = source_document.createElement(
"item");
160 QDomElement question_element = source_document.createElement(
"question");
161 QDomElement answer_element = source_document.createElement(
"answer");
162 QDomElement hint_element = source_document.createElement(
"hint");
163 QDomElement image_element = source_document.createElement(
"image");
165 question_element.appendChild(source_document.createTextNode(question.question()));
166 answer_element.appendChild(source_document.createTextNode(question.answer()));
167 hint_element.appendChild(source_document.createTextNode(question.hint()));
172 if (picture_encoded.isEmpty() || picture_encoded.isNull()) {
176 image_element.appendChild(source_document.createTextNode(QString::fromUtf8(picture_encoded)));
177 item_element.appendChild(question_element);
178 item_element.appendChild(answer_element);
179 item_element.appendChild(hint_element);
180 item_element.appendChild(image_element);
182 data_element.appendChild(item_element);
185 return source_document.toString(XML_BUNDLE_INDENTATION);
189 QDomDocument bundle_document;
190 bundle_document.setContent(bundle_data);
192 QDomNodeList items = bundle_document.documentElement().elementsByTagName(
"item");
194 for (
int i = 0; i < items.size(); i++) {
195 QDomNode item = items.at(i);
197 if (item.isElement()) {
198 QString question = item.namedItem(
"question").toElement().text();
199 QString answer = item.namedItem(
"answer").toElement().text();
200 QString hint = item.namedItem(
"hint").toElement().text();
201 QString image_data = item.namedItem(
"image").toElement().text();
203 if (question.isEmpty() || answer.isEmpty() || image_data.isEmpty()) {
210 QString output_directory = qApp->templateManager()->tempDirectory();
211 QString target_image_file = output_directory +
212 QString(
"/image_%1.png").arg(i);
216 addQuestion(question, answer, hint, target_image_file);
229 m_ui->m_txtAuthor->lineEdit()->setText(bundle_document.documentElement().namedItem(
"author").namedItem(
"name").toElement().text());
230 m_ui->m_txtName->lineEdit()->setText(bundle_document.documentElement().namedItem(
"title").toElement().text());
235 QList<FlashCardQuestion> FlashCardEditor::activeQuestions()
const {
236 QList<FlashCardQuestion> questions;
238 for (
int i = 0; i < m_ui->m_listQuestions->count(); i++) {
239 questions.append(m_ui->m_listQuestions->item(i)->data(Qt::UserRole).value<
FlashCardQuestion>());
246 return m_ui->m_txtName->lineEdit()->text();
250 return m_ui->m_txtAuthor->lineEdit()->text();
253 void FlashCardEditor::checkAuthor() {
254 if (m_ui->m_txtAuthor->lineEdit()->text().isEmpty()) {
255 m_ui->m_txtAuthor->setStatus(WidgetWithStatus::Error,
256 tr(
"No author is specified."));
259 m_ui->m_txtAuthor->setStatus(WidgetWithStatus::Ok,
260 tr(
"Author is specified."));
264 void FlashCardEditor::checkHint() {
265 if (m_ui->m_txtHint->lineEdit()->text().isEmpty()) {
266 m_ui->m_txtHint->setStatus(WidgetWithStatus::Warning,
267 tr(
"Hint is not specified."));
270 m_ui->m_txtHint->setStatus(WidgetWithStatus::Ok,
271 tr(
"Hint is specified."));
275 void FlashCardEditor::checkQuestion() {
276 if (m_ui->m_txtQuestion->lineEdit()->text().isEmpty()) {
277 m_ui->m_txtQuestion->setStatus(WidgetWithStatus::Warning,
278 tr(
"Question is not specified."));
281 m_ui->m_txtQuestion->setStatus(WidgetWithStatus::Ok,
282 tr(
"Question is specified."));
286 void FlashCardEditor::checkAnswer() {
287 if (m_ui->m_txtAnswer->lineEdit()->text().isEmpty()) {
288 m_ui->m_txtAnswer->setStatus(WidgetWithStatus::Error,
289 tr(
"Answer is not specified."));
292 m_ui->m_txtAnswer->setStatus(WidgetWithStatus::Ok,
293 tr(
"Answer is specified."));
297 void FlashCardEditor::checkName() {
298 if (m_ui->m_txtName->lineEdit()->text().isEmpty()) {
299 m_ui->m_txtName->setStatus(WidgetWithStatus::Error,
300 tr(
"No collection name is specified."));
303 m_ui->m_txtName->setStatus(WidgetWithStatus::Ok,
304 tr(
"Collection name is specified."));
308 void FlashCardEditor::configureUpDown() {
309 if (m_ui->m_listQuestions->count() > 1) {
310 int index = m_ui->m_listQuestions->currentRow();
313 m_ui->m_btnQuestionUp->setEnabled(
false);
314 m_ui->m_btnQuestionDown->setEnabled(
true);
316 else if (index == m_ui->m_listQuestions->count() - 1) {
317 m_ui->m_btnQuestionUp->setEnabled(
true);
318 m_ui->m_btnQuestionDown->setEnabled(
false);
321 m_ui->m_btnQuestionUp->setEnabled(
true);
322 m_ui->m_btnQuestionDown->setEnabled(
true);
326 m_ui->m_btnQuestionUp->setEnabled(
false);
327 m_ui->m_btnQuestionDown->setEnabled(
false);
331 void FlashCardEditor::moveQuestionUp() {
332 int index = m_ui->m_listQuestions->currentRow();
334 m_ui->m_listQuestions->insertItem(index - 1, m_ui->m_listQuestions->takeItem(index));
335 m_ui->m_listQuestions->setCurrentRow(index - 1);
340 void FlashCardEditor::moveQuestionDown() {
341 int index = m_ui->m_listQuestions->currentRow();
343 m_ui->m_listQuestions->insertItem(index + 1, m_ui->m_listQuestions->takeItem(index));
344 m_ui->m_listQuestions->setCurrentRow(index + 1);
349 void FlashCardEditor::loadPicture(
const QString& picture_path) {
350 if (!picture_path.isEmpty()) {
351 m_ui->m_lblPictureView->setPixmap(QPixmap(picture_path).scaled(m_ui->m_lblPictureView->size(),
352 Qt::KeepAspectRatio));
353 m_ui->m_lblPictureFile->setStatus(WidgetWithStatus::Ok,
354 tr(
"Picture is selected."),
355 tr(
"Picture is selected."));
358 m_ui->m_lblPictureView->setPixmap(QPixmap());
359 m_ui->m_lblPictureFile->setStatus(WidgetWithStatus::Error,
360 tr(
"Picture is not selected."),
361 tr(
"No picture is selected."));
364 m_ui->m_lblPictureFile->label()->setToolTip(QDir::toNativeSeparators(picture_path));
367 void FlashCardEditor::addQuestion(
const QString &question,
368 const QString &answer,
370 const QString &picture_path) {
371 int marked_question = m_ui->m_listQuestions->currentRow();
373 QListWidgetItem *new_item =
new QListWidgetItem();
375 new_question.setQuestion(question);
376 new_question.setHint(hint);
377 new_question.setAnswer(answer);
378 new_question.setPicturePath(picture_path);
380 new_item->setText(new_question.question());
381 new_item->setData(Qt::UserRole, QVariant::fromValue(new_question));
383 if (m_ui->m_listQuestions->count() == 0) {
385 setEditorsEnabled(
true);
387 m_ui->m_btnQuestionRemove->setEnabled(
true);
389 m_ui->m_listQuestions->insertItem(0, new_item);
390 m_ui->m_listQuestions->setCurrentRow(0);
393 m_ui->m_listQuestions->insertItem(marked_question + 1, new_item);
394 m_ui->m_listQuestions->setCurrentRow(marked_question + 1);
397 updateQuestionCount();
400 void FlashCardEditor::addQuestion() {
401 addQuestion(tr(
"What animal do you see on the picture?"),
403 tr(
"This animal is hated by dog."),
404 APP_TEMPLATES_PATH + QDir::separator() +
405 core()->entryPoint()->baseFolder() + QDir::separator() +
411 void FlashCardEditor::setEditorsEnabled(
bool enabled) {
412 m_ui->m_groupQuestionEditor->setEnabled(enabled);
415 void FlashCardEditor::loadQuestion(
int index) {
416 m_ui->m_txtQuestion->blockSignals(
true);
417 m_ui->m_lblPictureFile->label()->blockSignals(
true);
422 m_ui->m_txtQuestion->lineEdit()->setText(question.question());
423 m_ui->m_txtAnswer->lineEdit()->setText(question.answer());
424 m_ui->m_txtHint->lineEdit()->setText(question.hint());
425 loadPicture(question.picturePath());
427 m_activeQuestion = question;
430 m_ui->m_txtQuestion->lineEdit()->setText(QString());
431 m_ui->m_txtAnswer->lineEdit()->setText(QString());
432 m_ui->m_txtHint->lineEdit()->setText(QString());
433 loadPicture(QString());
436 m_ui->m_txtQuestion->blockSignals(
false);
437 m_ui->m_lblPictureFile->label()->blockSignals(
false);
442 QTimer::singleShot(0,
this, SLOT(configureUpDown()));
445 void FlashCardEditor::saveQuestion() {
446 m_activeQuestion.setQuestion(m_ui->m_txtQuestion->lineEdit()->text());
447 m_activeQuestion.setAnswer(m_ui->m_txtAnswer->lineEdit()->text());
448 m_activeQuestion.setHint(m_ui->m_txtHint->lineEdit()->text());
449 m_activeQuestion.setPicturePath(m_ui->m_lblPictureFile->label()->toolTip());
451 m_ui->m_listQuestions->currentItem()->setData(Qt::UserRole, QVariant::fromValue(m_activeQuestion));
452 m_ui->m_listQuestions->currentItem()->setText(m_activeQuestion.question());
457 void FlashCardEditor::removeQuestion() {
458 int current_row = m_ui->m_listQuestions->currentRow();
460 if (current_row >= 0) {
461 if (m_ui->m_listQuestions->count() == 1) {
463 setEditorsEnabled(
false);
465 m_ui->m_btnQuestionRemove->setEnabled(
false);
468 delete m_ui->m_listQuestions->takeItem(current_row);
471 updateQuestionCount();
476 void FlashCardEditor::onAnswerChanged(
const QString& new_answer) {
509 QString selected_picture = QFileDialog::getOpenFileName(
this, tr(
"Select picture for question"),
510 m_ui->m_lblPictureFile->label()->toolTip(),
511 tr(
"Images (*.gif *.jpg *.png)"),
514 if (!selected_picture.isEmpty()) {
515 loadPicture(selected_picture);
static bool base64ToFile(const QString &source_data, const QString &target_file)
Takes base64 byte array and saves it into file.
bool loadBundleData(const QString &bundle_data)
Loads editor state from XML bundle.
TemplateCore * core() const
Access to associated template core.
static QByteArray fileToBase64(const QString &file_name)
Takes input file and reads it into base64 byte array.
void changed()
Emitted everytime any child widget of editor changes its contents.
Represents the editor of the template.
Icon theme manipulator and provider.
QString authorName()
Access to author name of current editor.
The core class container for single template.
QString projectName()
Access to project name of current editor.
QIcon fromTheme(const QString &name)
Returns icon from active theme.
virtual void launch()
Executed when given template with this editor is launched.
QString generateBundleData()
Generates RAW data which represent data of this template.
static IconFactory * instance()
Singleton getter.
bool canGenerateApplications()
Specifies if template can generate applications or not.