File indexing completed on 2023-05-30 10:45:25
0001 /* 0002 SPDX-FileCopyrightText: 2002-2010 Peter Hedlund <peter.hedlund@kdemail.net> 0003 SPDX-License-Identifier: GPL-2.0-or-later 0004 */ 0005 0006 #include "kwordquiz.h" 0007 0008 #include <QBitmap> 0009 #include <QCheckBox> 0010 #include <QDBusInterface> 0011 #include <QDBusReply> 0012 #include <QDebug> 0013 #include <QFileDialog> 0014 #include <QFontDialog> 0015 #include <QIcon> 0016 #include <QMenu> 0017 #include <QMimeDatabase> 0018 #include <QMimeType> 0019 #include <QPainter> 0020 #include <QPointer> 0021 #include <QStandardPaths> 0022 #include <QStatusBar> 0023 #include <QTemporaryFile> 0024 0025 #include <KActionCollection> 0026 #include <KActionMenu> 0027 #include <KConfigGroup> 0028 #include <KLocalizedString> 0029 #include <KMessageBox> 0030 #include <KNotifyConfigWidget> 0031 #include <KPageWidget> 0032 #include <KProcess> 0033 #include <KToggleAction> 0034 #include <KToolBar> 0035 #include <KUndoActions> 0036 #include <KXMLGUIFactory> 0037 0038 #include "keduvoclesson.h" 0039 #include "keduvocexpression.h" 0040 #include "kwqtablemodel.h" 0041 #include "kwqsortfiltermodel.h" 0042 #include "kwqtableview.h" 0043 #include "kwqcommands.h" 0044 #include "dlglanguage.h" 0045 #include "kwordquizprefs.h" 0046 #include "qaview.h" 0047 #include "flashview.h" 0048 #include "multipleview.h" 0049 #include "wqprintdialogpage.h" 0050 #include "prefs.h" 0051 #include "kwordquiz_version.h" 0052 #include <kwidgetsaddons_version.h> 0053 0054 KWordQuizApp::KWordQuizApp(QWidget*):KXmlGuiWindow(0) 0055 { 0056 m_quiz = 0; 0057 m_prefDialog = 0; 0058 0059 initStatusBar(); 0060 initActions(); 0061 initDocument(); 0062 initModel(); 0063 0064 readOptions(); 0065 0066 initView(); 0067 0068 m_dirWatch = KDirWatch::self(); 0069 0070 slotModeActionGroupTriggered(m_modeActionGroup->actions().at(Prefs::mode() - 1)); 0071 0072 editMarkBlank->setEnabled(Prefs::enableBlanks()); 0073 editUnmarkBlank->setEnabled(Prefs::enableBlanks()); 0074 0075 if (Prefs::firstRun()) 0076 { 0077 fileOpenRecent->addUrl(QUrl::fromLocalFile(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kwordquiz/examples/example.kvtml")))); 0078 fileOpenRecent->addUrl(QUrl::fromLocalFile(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kwordquiz/examples/french_verbs.kvtml")))); 0079 fileOpenRecent->addUrl(QUrl::fromLocalFile(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kwordquiz/examples/fill_in_the_blank.kvtml")))); 0080 fileOpenRecent->addUrl(QUrl::fromLocalFile(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kwordquiz/examples/us_states_and_capitals.kvtml")))); 0081 Prefs::setFirstRun(false); 0082 } 0083 } 0084 0085 KWordQuizApp::~KWordQuizApp() 0086 { 0087 disconnect(m_undoStack, &QUndoStack::undoTextChanged, this, &KWordQuizApp::slotUndoTextChanged); 0088 disconnect(m_undoStack, &QUndoStack::redoTextChanged, this, &KWordQuizApp::slotRedoTextChanged); 0089 } 0090 0091 void KWordQuizApp::initActions() 0092 { 0093 QAction* configToolbar; 0094 QAction* configNotifications; 0095 QAction* configApp; 0096 0097 QAction * a; 0098 0099 fileNew = KStandardAction::openNew(this, SLOT(slotFileNew()), actionCollection()); 0100 fileNew->setWhatsThis(i18n("Creates a new blank vocabulary document")); 0101 fileNew->setToolTip(fileNew->whatsThis()); 0102 fileNew->setStatusTip(fileNew->whatsThis()); 0103 0104 fileOpen = KStandardAction::open(this, SLOT(slotFileOpen()), actionCollection()); 0105 fileOpen->setWhatsThis(i18n("Opens an existing vocabulary document")); 0106 fileOpen->setToolTip(fileOpen->whatsThis()); 0107 fileOpen->setStatusTip(fileOpen->whatsThis()); 0108 0109 fileOpenRecent = KStandardAction::openRecent(this, SLOT(slotFileOpenRecent(QUrl)), actionCollection()); 0110 0111 KNSWidgets::Action *fileGHNS = new KNSWidgets::Action(i18n("Download New Vocabularies..."), QStringLiteral("kwordquiz.knsrc"), this); 0112 connect(fileGHNS, &KNSWidgets::Action::dialogFinished, this, &KWordQuizApp::slotFileGHNS); 0113 actionCollection()->addAction(QStringLiteral("file_ghns"), fileGHNS); 0114 actionCollection()->setDefaultShortcut(fileGHNS, QKeySequence(Qt::CTRL | Qt::Key_G)); 0115 fileGHNS->setWhatsThis(i18n("Downloads new vocabularies")); 0116 fileGHNS->setToolTip(fileGHNS->whatsThis()); 0117 fileGHNS->setStatusTip(fileGHNS->whatsThis()); 0118 0119 fileSave = KStandardAction::save(this, SLOT(slotFileSave()), actionCollection()); 0120 fileSave->setWhatsThis(i18n("Saves the active vocabulary document")); 0121 fileSave->setToolTip(fileSave->whatsThis()); 0122 fileSave->setStatusTip(fileSave->whatsThis()); 0123 0124 fileSaveAs = KStandardAction::saveAs(this, SLOT(slotFileSaveAs()), actionCollection()); 0125 fileSaveAs->setWhatsThis(i18n("Saves the active vocabulary document with a different name")); 0126 fileSaveAs->setToolTip(fileSaveAs->whatsThis()); 0127 fileSaveAs->setStatusTip(fileSaveAs->whatsThis()); 0128 0129 fileClose = KStandardAction::close(this, SLOT(slotFileClose()), actionCollection()); 0130 fileClose->setWhatsThis(i18n("Closes the active vocabulary document")); 0131 fileClose->setStatusTip(fileClose->whatsThis()); 0132 0133 filePrint = KStandardAction::print(this, SLOT(slotFilePrint()), actionCollection()); 0134 filePrint->setWhatsThis(i18n("Prints the active vocabulary document")); 0135 filePrint->setToolTip(filePrint->whatsThis()); 0136 filePrint->setStatusTip(filePrint->whatsThis()); 0137 0138 filePrintPreview = KStandardAction::printPreview(this, SLOT(slotFilePrintPreview()), actionCollection()); 0139 filePrintPreview->setWhatsThis(i18n("Shows a preview of the active vocabulary document")); 0140 filePrintPreview->setToolTip(filePrintPreview->whatsThis()); 0141 filePrintPreview->setStatusTip(filePrintPreview->whatsThis()); 0142 0143 fileQuit = KStandardAction::quit(this, SLOT(slotFileQuit()), actionCollection()); 0144 fileQuit->setWhatsThis(i18n("Quits KWordQuiz")); 0145 fileQuit->setToolTip(fileQuit->whatsThis()); 0146 fileQuit->setStatusTip(fileQuit->whatsThis()); 0147 0148 m_undoStack = new QUndoStack(this); 0149 editUndo = KUndoActions::createUndoAction(m_undoStack, actionCollection()); 0150 editRedo = KUndoActions::createRedoAction(m_undoStack, actionCollection()); 0151 connect(m_undoStack, &QUndoStack::cleanChanged, this, &KWordQuizApp::slotCleanChanged); 0152 connect(m_undoStack, &QUndoStack::undoTextChanged, this, &KWordQuizApp::slotUndoTextChanged); 0153 connect(m_undoStack, &QUndoStack::redoTextChanged, this, &KWordQuizApp::slotRedoTextChanged); 0154 0155 editCut = KStandardAction::cut(this, SLOT(slotEditCut()), actionCollection()); 0156 editCut->setWhatsThis(i18n("Cuts the text from the selected cells and places it on the clipboard")); 0157 editCut->setToolTip(editCut->whatsThis()); 0158 editCut->setStatusTip(editCut->whatsThis()); 0159 0160 editCopy = KStandardAction::copy(this, SLOT(slotEditCopy()), actionCollection()); 0161 editCopy->setWhatsThis(i18n("Copies the text from the selected cells and places it on the clipboard")); 0162 editCopy->setToolTip(editCopy->whatsThis()); 0163 editCopy->setStatusTip(editCopy->whatsThis()); 0164 0165 editPaste = KStandardAction::paste(this, SLOT(slotEditPaste()), actionCollection()); 0166 editPaste->setWhatsThis(i18n("Pastes previously cut or copied text from the clipboard into the selected cells")); 0167 editPaste->setToolTip(editPaste->whatsThis()); 0168 editPaste->setStatusTip(editPaste->whatsThis()); 0169 0170 editClear = KStandardAction::clear(this, SLOT(slotEditClear()), actionCollection()); 0171 actionCollection()->setDefaultShortcut(editClear, Qt::Key_Delete); 0172 editClear->setWhatsThis(i18n("Clears the content of the selected cells")); 0173 editClear->setToolTip(editClear->whatsThis()); 0174 editClear->setStatusTip(editClear->whatsThis()); 0175 0176 editInsert = actionCollection()->addAction(QStringLiteral("edit_insert")); 0177 editInsert->setIcon(QIcon::fromTheme(QStringLiteral("insert-table-row"))); 0178 editInsert->setText(i18n("&Insert Row")); 0179 actionCollection()->setDefaultShortcut(editInsert, QKeySequence(Qt::CTRL | Qt::Key_I)); 0180 editInsert->setWhatsThis(i18n("Inserts a new row above the current row")); 0181 editInsert->setToolTip(editInsert->whatsThis()); 0182 editInsert->setStatusTip(editInsert->whatsThis()); 0183 connect(editInsert, &QAction::triggered, this, &KWordQuizApp::slotEditInsert); 0184 0185 editDelete = actionCollection()->addAction(QStringLiteral("edit_delete")); 0186 editDelete->setIcon(QIcon::fromTheme(QStringLiteral("delete-table-row"))); 0187 editDelete->setText(i18n("&Delete Row")); 0188 actionCollection()->setDefaultShortcut(editDelete, QKeySequence(Qt::CTRL | Qt::Key_K)); 0189 editDelete->setWhatsThis(i18n("Deletes the selected row(s)")); 0190 editDelete->setToolTip(editDelete->whatsThis()); 0191 editDelete->setStatusTip(editDelete->whatsThis()); 0192 connect(editDelete, &QAction::triggered, this, &KWordQuizApp::slotEditDelete); 0193 0194 editMarkBlank = actionCollection()->addAction(QStringLiteral("edit_mark_blank")); 0195 editMarkBlank->setIcon(QIcon::fromTheme(QStringLiteral("markasblank"))); 0196 editMarkBlank->setText(i18n("&Mark as Blank")); 0197 actionCollection()->setDefaultShortcut(editMarkBlank, QKeySequence(Qt::CTRL | Qt::Key_M)); 0198 editMarkBlank->setWhatsThis(i18n("Marks the current or selected word as a blank for Fill-in-the-blank")); 0199 editMarkBlank->setToolTip(editMarkBlank->whatsThis()); 0200 editMarkBlank->setStatusTip(editMarkBlank->whatsThis()); 0201 connect(editMarkBlank, &QAction::triggered, this, &KWordQuizApp::slotEditMarkBlank); 0202 0203 editUnmarkBlank = actionCollection()->addAction(QStringLiteral("edit_unmark_blank")); 0204 editUnmarkBlank->setIcon(QIcon::fromTheme(QStringLiteral("unmarkasblank"))); 0205 editUnmarkBlank->setText(i18n("&Unmark Blanks")); 0206 editUnmarkBlank->setWhatsThis(i18n("Removes blanks from the current or selected word")); 0207 editUnmarkBlank->setToolTip(editUnmarkBlank->whatsThis()); 0208 editUnmarkBlank->setStatusTip(editUnmarkBlank->whatsThis()); 0209 connect(editUnmarkBlank, &QAction::triggered, this, &KWordQuizApp::slotEditUnmarkBlank); 0210 0211 vocabLanguages = actionCollection()->addAction(QStringLiteral("vocab_languages")); 0212 vocabLanguages->setIcon(QIcon::fromTheme(QStringLiteral("languages"))); 0213 vocabLanguages->setText(i18n("&Column Settings...")); 0214 actionCollection()->setDefaultShortcut(vocabLanguages, QKeySequence(Qt::CTRL | Qt::Key_L)); 0215 vocabLanguages->setWhatsThis(i18n("Defines the column settings for the active vocabulary")); 0216 vocabLanguages->setToolTip(vocabLanguages->whatsThis()); 0217 vocabLanguages->setStatusTip(vocabLanguages->whatsThis()); 0218 connect(vocabLanguages, &QAction::triggered, this, &KWordQuizApp::slotVocabLanguages); 0219 0220 vocabFont = actionCollection()->addAction(QStringLiteral("vocab_font")); 0221 vocabFont->setIcon(QIcon::fromTheme(QStringLiteral("preferences-desktop-font"))); 0222 vocabFont->setText(i18n("&Font...")); 0223 vocabFont->setWhatsThis(i18n("Defines the font used by the editor")); 0224 vocabFont->setToolTip(vocabFont->whatsThis()); 0225 vocabFont->setStatusTip(vocabFont->whatsThis()); 0226 connect(vocabFont, &QAction::triggered, this, &KWordQuizApp::slotVocabFont); 0227 0228 a = actionCollection()->addAction(QStringLiteral("vocab_image")); 0229 a->setIcon(QIcon::fromTheme(QStringLiteral("image-x-generic"))); 0230 a->setText(i18n("Link &Image...")); 0231 a->setWhatsThis(i18n("Links an image with the current entry")); 0232 a->setToolTip(a->whatsThis()); 0233 a->setStatusTip(a->whatsThis()); 0234 connect(a, &QAction::triggered, this, &KWordQuizApp::slotVocabImage); 0235 0236 a = actionCollection()->addAction(QStringLiteral("vocab_sound")); 0237 a->setIcon(QIcon::fromTheme(QStringLiteral("audio-x-generic"))); 0238 a->setText(i18n("Link &Sound...")); 0239 a->setWhatsThis(i18n("Links a sound with the current entry")); 0240 a->setToolTip(a->whatsThis()); 0241 a->setStatusTip(a->whatsThis()); 0242 connect(a, &QAction::triggered, this, &KWordQuizApp::slotVocabSound); 0243 0244 vocabAdjustRows = actionCollection()->addAction(QStringLiteral("vocab_adjust_rows")); 0245 //vocabAdjustRows->setIcon(QIcon::fromTheme()); 0246 vocabAdjustRows->setText(i18n("&Adjust Row Heights")); 0247 vocabAdjustRows->setWhatsThis(i18n("Automatically adjusts the height of selected rows")); 0248 vocabAdjustRows->setToolTip(vocabAdjustRows->whatsThis()); 0249 vocabAdjustRows->setStatusTip(vocabAdjustRows->whatsThis()); 0250 connect(vocabAdjustRows, &QAction::triggered, this, &KWordQuizApp::slotVocabAdjustRows); 0251 0252 vocabShuffle = actionCollection()->addAction(QStringLiteral("vocab_shuffle")); 0253 vocabShuffle->setIcon(QIcon::fromTheme(QStringLiteral("shuffle"))); 0254 vocabShuffle->setText(i18n("Sh&uffle")); 0255 vocabShuffle->setWhatsThis(i18n("Shuffles the entries of the active vocabulary")); 0256 vocabShuffle->setToolTip(vocabShuffle->whatsThis()); 0257 vocabShuffle->setStatusTip(vocabShuffle->whatsThis()); 0258 connect(vocabShuffle, &QAction::triggered, this, &KWordQuizApp::slotVocabShuffle); 0259 0260 vocabLayouts = actionCollection()->addAction(QStringLiteral("vocab_layouts")); 0261 vocabLayouts->setText(i18n("&Keyboard Layout")); 0262 vocabLayouts->setWhatsThis(i18n("Shows available keyboard layouts")); 0263 vocabLayouts->setToolTip(vocabLayouts->whatsThis()); 0264 vocabLayouts->setStatusTip(vocabLayouts->whatsThis()); 0265 QMenu *m = new QMenu(this); 0266 vocabLayouts->setMenu(m); 0267 0268 m_layoutActionGroup = new QActionGroup(this); 0269 connect(m_layoutActionGroup, &QActionGroup::triggered, this, &KWordQuizApp::slotLayoutActionGroupTriggered); 0270 0271 m_modeActionMenu = actionCollection()->add<KActionMenu>(QStringLiteral("mode_0")); 0272 m_modeActionMenu->setIcon(QIcon::fromTheme(QStringLiteral("mode1"))); 0273 m_modeActionMenu->setText(i18n("Change Mode")); 0274 m_modeActionMenu->setIconText(i18n("Mode")); 0275 m_modeActionMenu->setWhatsThis(i18n("Changes the mode used in quiz sessions")); 0276 m_modeActionMenu->setToolTip(m_modeActionMenu->whatsThis()); 0277 m_modeActionMenu->setStatusTip(m_modeActionMenu->whatsThis()); 0278 connect(m_modeActionMenu, &QAction::triggered, this, &KWordQuizApp::slotModeChange); 0279 0280 m_modeActionGroup = new QActionGroup(this); 0281 connect(m_modeActionGroup, &QActionGroup::triggered, this, &KWordQuizApp::slotModeActionGroupTriggered); 0282 0283 for (int i = 1; i <=5; ++i) { 0284 a = actionCollection()->addAction(QStringLiteral("mode_%1").arg(QString::number(i))); 0285 a->setData(i); 0286 a->setCheckable(true); 0287 a->setIcon(QIcon::fromTheme(QStringLiteral("mode%1").arg(QString::number(i)))); 0288 a->setWhatsThis(i18n("Selects this mode")); 0289 a->setToolTip(a->whatsThis()); 0290 a->setStatusTip(a->whatsThis()); 0291 m_modeActionMenu->addAction(a); 0292 m_modeActionGroup->addAction(a); 0293 } 0294 0295 quizEditor = actionCollection()->addAction(QStringLiteral("quiz_editor")); 0296 quizEditor->setIcon(QIcon::fromTheme(QStringLiteral("editor"))); 0297 quizEditor->setText(i18nc("@item:inlistbox activate vocabulary editor", "&Editor")); 0298 actionCollection()->setDefaultShortcut(quizEditor, QKeySequence(Qt::Key_F6)); 0299 quizEditor->setWhatsThis(i18n("Activates the vocabulary editor")); 0300 quizEditor->setToolTip(quizEditor->whatsThis()); 0301 quizEditor->setStatusTip(quizEditor->whatsThis()); 0302 connect(quizEditor, &QAction::triggered, this, &KWordQuizApp::slotQuizEditor); 0303 0304 quizFlash = actionCollection()->addAction(QStringLiteral("quiz_flash")); 0305 quizFlash->setIcon(QIcon::fromTheme(QStringLiteral("flash"))); 0306 quizFlash->setText(i18n("&Flashcard")); 0307 actionCollection()->setDefaultShortcut(quizFlash, QKeySequence(Qt::Key_F7)); 0308 quizFlash->setWhatsThis(i18n("Starts a flashcard session using the active vocabulary")); 0309 quizFlash->setToolTip(quizFlash->whatsThis()); 0310 quizFlash->setStatusTip(quizFlash->whatsThis()); 0311 connect(quizFlash, &QAction::triggered, this, &KWordQuizApp::slotQuizFlash); 0312 0313 quizMultiple = actionCollection()->addAction(QStringLiteral("quiz_multiple")); 0314 quizMultiple->setIcon(QIcon::fromTheme(QStringLiteral("multiple"))); 0315 quizMultiple->setText(i18n("&Multiple Choice")); 0316 actionCollection()->setDefaultShortcut(quizMultiple, QKeySequence(Qt::Key_F8)); 0317 quizMultiple->setWhatsThis(i18n("Starts a multiple choice session using the active vocabulary")); 0318 quizMultiple->setToolTip(quizMultiple->whatsThis()); 0319 quizMultiple->setStatusTip(quizMultiple->whatsThis()); 0320 connect(quizMultiple, &QAction::triggered, this, &KWordQuizApp::slotQuizMultiple); 0321 0322 quizQA = actionCollection()->addAction(QStringLiteral("quiz_qa")); 0323 quizQA->setIcon(QIcon::fromTheme(QStringLiteral("qa"))); 0324 quizQA->setText(i18n("&Question and Answer")); 0325 quizQA->setIconText(i18n("Q&&A")); 0326 actionCollection()->setDefaultShortcut(quizQA, QKeySequence(Qt::Key_F9)); 0327 quizQA->setWhatsThis(i18n("Starts a question and answer session using the active vocabulary")); 0328 quizQA->setToolTip(quizQA->whatsThis()); 0329 quizQA->setStatusTip(quizQA->whatsThis()); 0330 connect(quizQA, &QAction::triggered, this, &KWordQuizApp::slotQuizQA); 0331 0332 quizCheck = actionCollection()->addAction(QStringLiteral("quiz_check")); 0333 quizCheck->setIcon(QIcon::fromTheme(QStringLiteral("answer-correct"))); 0334 quizCheck->setText(i18n("&Check")); 0335 actionCollection()->setDefaultShortcut(quizCheck, QKeySequence(Qt::Key_Return)); 0336 quizCheck->setWhatsThis(i18n("Checks your answer to this question")); 0337 quizCheck->setToolTip(quizCheck->whatsThis()); 0338 quizCheck->setStatusTip(quizCheck->whatsThis()); 0339 0340 quizOpt1 = actionCollection()->addAction(QStringLiteral("quiz_Opt1")); 0341 quizOpt1->setText(i18n("Choose Option &1")); 0342 actionCollection()->setDefaultShortcut(quizOpt1, QKeySequence(Qt::Key_1)); 0343 0344 quizOpt2 = actionCollection()->addAction(QStringLiteral("quiz_Opt2")); 0345 quizOpt2->setText(i18n("Choose Option &2")); 0346 actionCollection()->setDefaultShortcut(quizOpt2, QKeySequence(Qt::Key_2)); 0347 0348 quizOpt3 = actionCollection()->addAction(QStringLiteral("quiz_Opt3")); 0349 quizOpt3->setText(i18n("Choose Option &3")); 0350 actionCollection()->setDefaultShortcut(quizOpt3, QKeySequence(Qt::Key_3)); 0351 0352 flashKnow = actionCollection()->addAction(QStringLiteral("flash_know")); 0353 flashKnow->setIcon(QIcon::fromTheme(QStringLiteral("know"))); 0354 flashKnow->setText(i18n("I &Know")); 0355 actionCollection()->setDefaultShortcut(flashKnow, QKeySequence(Qt::Key_K)); 0356 flashKnow->setWhatsThis(i18n("Counts this card as correct and shows the next card")); 0357 flashKnow->setToolTip(flashKnow->whatsThis()); 0358 flashKnow->setStatusTip(flashKnow->whatsThis()); 0359 0360 flashDontKnow = actionCollection()->addAction(QStringLiteral("flash_dont_know")); 0361 flashDontKnow->setIcon(QIcon::fromTheme(QStringLiteral("dontknow"))); 0362 flashDontKnow->setText(i18n("I &Do Not Know")); 0363 actionCollection()->setDefaultShortcut(flashDontKnow, QKeySequence(Qt::Key_D)); 0364 flashDontKnow->setWhatsThis(i18n("Counts this card as incorrect and shows the next card")); 0365 flashDontKnow->setToolTip(flashDontKnow->whatsThis()); 0366 flashDontKnow->setStatusTip(flashDontKnow->whatsThis()); 0367 0368 qaHint = actionCollection()->addAction(QStringLiteral("qa_hint")); 0369 qaHint->setIcon(QIcon::fromTheme(QStringLiteral("hint"))); 0370 qaHint->setText(i18n("&Hint")); 0371 actionCollection()->setDefaultShortcut(qaHint, QKeySequence(Qt::CTRL | Qt::Key_H)); 0372 qaHint->setWhatsThis(i18n("Gets the next correct letter of the answer")); 0373 qaHint->setToolTip(qaHint->whatsThis()); 0374 qaHint->setStatusTip(qaHint->whatsThis()); 0375 0376 qaMarkLastCorrect = actionCollection()->addAction(QStringLiteral("qa_mark_last_correct")); 0377 qaMarkLastCorrect->setIcon(QIcon::fromTheme(QStringLiteral("answer-correct"))); 0378 qaMarkLastCorrect->setText(i18n("Mark Last Correct")); 0379 actionCollection()->setDefaultShortcut(qaMarkLastCorrect, QKeySequence(Qt::SHIFT | Qt::Key_Return)); 0380 qaMarkLastCorrect->setWhatsThis(i18n("Marks last answer as correct")); 0381 qaMarkLastCorrect->setToolTip(qaMarkLastCorrect->whatsThis()); 0382 qaMarkLastCorrect->setStatusTip(qaMarkLastCorrect->whatsThis()); 0383 0384 quizRestart = actionCollection()->addAction(QStringLiteral("quiz_restart")); 0385 quizRestart->setIcon(QIcon::fromTheme(QStringLiteral("start-over"))); 0386 quizRestart->setText(i18n("&Restart")); 0387 actionCollection()->setDefaultShortcut(quizRestart, QKeySequence(Qt::CTRL | Qt::Key_R)); 0388 quizRestart->setWhatsThis(i18n("Restarts the quiz session from the beginning")); 0389 quizRestart->setToolTip(quizRestart->whatsThis()); 0390 quizRestart->setStatusTip(quizRestart->whatsThis()); 0391 0392 a = actionCollection()->addAction(QStringLiteral("quiz_audio_play")); 0393 a->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-start"))); 0394 a->setText(i18n("&Play Audio")); 0395 actionCollection()->setDefaultShortcut(a, QKeySequence(Qt::CTRL | Qt::Key_B)); 0396 a->setWhatsThis(i18n("Play associated audio")); 0397 a->setToolTip(a->whatsThis()); 0398 a->setStatusTip(a->whatsThis()); 0399 0400 quizRepeatErrors = actionCollection()->addAction(QStringLiteral("quiz_repeat_errors")); 0401 quizRepeatErrors->setIcon(QIcon::fromTheme(QStringLiteral("repeat"))); 0402 quizRepeatErrors->setText(i18n("Repeat &Errors")); 0403 actionCollection()->setDefaultShortcut(quizRepeatErrors, QKeySequence(Qt::CTRL | Qt::Key_E)); 0404 quizRepeatErrors->setWhatsThis(i18n("Repeats all incorrectly answered questions")); 0405 quizRepeatErrors->setToolTip(quizRepeatErrors->whatsThis()); 0406 quizRepeatErrors->setStatusTip(quizRepeatErrors->whatsThis()); 0407 0408 quizExportErrors = actionCollection()->addAction(QStringLiteral("quiz_export_errors")); 0409 quizExportErrors->setIcon(KStandardGuiItem::saveAs().icon()); 0410 quizExportErrors->setText(i18n("Export Errors &As...")); 0411 quizExportErrors->setWhatsThis(i18n("Exports all errors as a new vocabulary document")); 0412 quizExportErrors->setToolTip(quizExportErrors->whatsThis()); 0413 quizExportErrors->setStatusTip(quizExportErrors->whatsThis()); 0414 connect(quizExportErrors, &QAction::triggered, this, &KWordQuizApp::slotCreateErrorListDocument); 0415 0416 configShowSearchBar = actionCollection()->add<KToggleAction>(QStringLiteral("config_show_search")); 0417 configShowSearchBar->setText(i18n("Show Se&arch")); 0418 connect(configShowSearchBar, &QAction::triggered, this, &KWordQuizApp::slotConfigShowSearch); 0419 configShowSearchBar->setWhatsThis(i18n("Toggle display of the search bar")); 0420 configShowSearchBar->setToolTip(configShowSearchBar->whatsThis()); 0421 configShowSearchBar->setStatusTip(configShowSearchBar->whatsThis()); 0422 0423 configNotifications = KStandardAction::configureNotifications(this, SLOT(slotConfigureNotifications()), actionCollection()); 0424 configNotifications->setWhatsThis(i18n("Configures sound and other notifications for certain events")); 0425 configNotifications->setToolTip(configNotifications->whatsThis()); 0426 configNotifications->setStatusTip(configNotifications->whatsThis()); 0427 0428 configApp = KStandardAction::preferences(this, SLOT(slotConfigure()), actionCollection()); 0429 configApp->setWhatsThis(i18n("Specifies preferences for the vocabulary editor and quiz sessions")); 0430 configApp->setToolTip(configApp->whatsThis()); 0431 configApp->setStatusTip(configApp->whatsThis()); 0432 0433 for (int i = 1; i <=9; ++i) { 0434 a = actionCollection()->addAction(QStringLiteral("char_%1").arg(QString::number(i))); 0435 a->setText(i18n("Special Character <numid>%1</numid>", i)); 0436 actionCollection()->setDefaultShortcut(a, QKeySequence(QStringLiteral("Ctrl+%1").arg(QString::number(i)))); 0437 connect(a, &QAction::triggered, this, [this, i] () { slotInsertChar(i); }); 0438 } 0439 0440 updateSpecialCharIcons(); 0441 0442 resize( QSize(650, 450).expandedTo(minimumSizeHint())); 0443 setupGUI(ToolBar | Keys | StatusBar | Create); 0444 setAutoSaveSettings(); 0445 0446 configToolbar = actionCollection()->action(QStringLiteral("options_configure_toolbars")); 0447 configToolbar->setWhatsThis(i18n("Toggles display of the toolbars")); 0448 configToolbar->setToolTip(configToolbar->whatsThis()); 0449 configToolbar->setStatusTip(configToolbar->whatsThis()); 0450 } 0451 0452 void KWordQuizApp::initStatusBar() 0453 { 0454 m_statusLabel = new QLabel(statusBar()); 0455 statusBar()->insertPermanentWidget(0, m_statusLabel); 0456 //statusBar()->setItemFixed(1, 250); 0457 } 0458 0459 void KWordQuizApp::initDocument() 0460 { 0461 m_doc = new KEduVocDocument(this); 0462 m_doc->setGenerator(QStringLiteral("kwordquiz %1").arg(KWORDQUIZ_VERSION_STRING)); 0463 ///@todo New kvtml documents have a locale setting which should contain the language they are written in. 0464 /* it would be nice to support that somehow. get hot new stuff for KHangman and KAnagram already uses this. */ 0465 m_doc->appendIdentifier(); 0466 m_doc->identifier(0).setName(i18n("Column 1")); 0467 // m_doc->identifier(0).setLocale("en"); 0468 m_doc->appendIdentifier(); 0469 m_doc->identifier(1).setName(i18n("Column 2")); 0470 // m_doc->identifier(1).setLocale("en"); 0471 0472 for (int i=0; i<20; i++) 0473 { 0474 m_doc->lesson()->appendEntry(new KEduVocExpression()); 0475 } 0476 } 0477 0478 void KWordQuizApp::initModel() 0479 { 0480 m_tableModel = new KWQTableModel(this); 0481 m_tableModel->setDocument(m_doc); 0482 m_tableModel->setHeaderData(0, Qt::Horizontal, QSize(250, 25), Qt::SizeHintRole); 0483 m_tableModel->setHeaderData(1, Qt::Horizontal, QSize(250, 25), Qt::SizeHintRole); 0484 m_sortFilterModel = new KWQSortFilterModel(this); 0485 m_sortFilterModel->setTableModel(m_tableModel); 0486 } 0487 0488 void KWordQuizApp::initView() 0489 { 0490 m_pageWidget = new KPageWidget(this); 0491 m_pageWidget->setFaceType( KPageView::List ); 0492 setCentralWidget(m_pageWidget); 0493 connect(m_pageWidget, SIGNAL(currentPageChanged(KPageWidgetItem*,KPageWidgetItem*)), this, SLOT(slotCurrentPageChanged(KPageWidgetItem*,KPageWidgetItem*))); 0494 0495 QVBoxLayout *editorLayout = new QVBoxLayout(); 0496 editorLayout->setContentsMargins(0, 0, 0, 0); 0497 0498 m_searchLine = new FilterProxySearchLine(this); 0499 m_searchLine->setFocusPolicy(Qt::ClickFocus); 0500 m_searchLine->setPlaceholderText(i18n("Enter search terms here")); 0501 m_searchLine->setFilterProxyModel(m_sortFilterModel); 0502 0503 m_tableView = new KWQTableView(m_undoStack, this); 0504 editorLayout->addWidget(m_searchLine); 0505 editorLayout->addWidget(m_tableView); 0506 m_tableView->setFilterModel(m_sortFilterModel); 0507 m_tableView->setColumnWidth(0, qvariant_cast<QSize>(m_tableModel->headerData(0, Qt::Horizontal, Qt::SizeHintRole)).width()); 0508 m_tableView->setColumnWidth(1, qvariant_cast<QSize>(m_tableModel->headerData(1, Qt::Horizontal, Qt::SizeHintRole)).width()); 0509 setWindowTitle(m_doc->url().fileName() + QStringLiteral("[*]")); 0510 setWindowModified(false); 0511 m_tableView->setContextMenuPolicy(Qt::CustomContextMenu); 0512 connect(m_tableView, &QWidget::customContextMenuRequested, this, &KWordQuizApp::slotTableContextMenuRequested); 0513 connect(m_tableModel, &QAbstractItemModel::modelReset, m_tableView, &KWQTableView::slotModelReset); 0514 0515 m_searchLine->setVisible(Prefs::showSearch()); 0516 configShowSearchBar->setChecked(Prefs::showSearch()); 0517 0518 m_editorView = new QWidget(this); 0519 m_flashView = new FlashView(this, actionCollection()); 0520 m_multipleView = new MultipleView(this, actionCollection()); 0521 m_qaView = new QAView(this, actionCollection()); 0522 0523 m_editorPage = m_pageWidget->addPage(m_editorView, i18nc("@item:inlistbox vocabulary editor", "Editor")); 0524 m_editorPage->setIcon(QIcon::fromTheme(QStringLiteral("editor"))); 0525 m_editorPage->setHeader(QLatin1String("")); 0526 m_editorPage->widget()->setLayout(editorLayout); 0527 0528 m_flashPage = m_pageWidget->addPage(m_flashView, i18n("Flashcard")); 0529 m_flashPage->setIcon(QIcon::fromTheme(QStringLiteral("flash"))); 0530 m_flashPage->setHeader(QLatin1String("")); 0531 0532 m_multiplePage = m_pageWidget->addPage(m_multipleView, i18n("Multiple Choice")); 0533 m_multiplePage->setIcon(QIcon::fromTheme(QStringLiteral("multiple"))); 0534 m_multiplePage->setHeader(QLatin1String("")); 0535 0536 m_qaPage = m_pageWidget->addPage(m_qaView, i18n("Question & Answer")); 0537 m_qaPage->setIcon(QIcon::fromTheme(QStringLiteral("qa"))); 0538 m_qaPage->setHeader(QLatin1String("")); 0539 0540 m_pageWidget->addAction(quizEditor); 0541 m_pageWidget->addAction(quizFlash); 0542 m_pageWidget->addAction(quizMultiple); 0543 m_pageWidget->addAction(quizQA); 0544 0545 const QList<QObject*> listOfChildren = m_pageWidget->children(); 0546 0547 for (QObject *object : listOfChildren) { 0548 if(!object->isWidgetType()) 0549 continue; 0550 0551 QWidget *childWidget = static_cast<QWidget *>(object); 0552 0553 if (childWidget->inherits("QListView")) 0554 childWidget->setFocusPolicy(Qt::NoFocus); 0555 } 0556 0557 m_pageWidget->setCurrentPage(m_editorPage); 0558 m_tableView->setFocus(); 0559 updateActions(); 0560 } 0561 0562 void KWordQuizApp::openUrl(const QUrl &url) 0563 { 0564 if(!url.isEmpty()) { 0565 if (m_dirWatch->contains(url.path())) 0566 { 0567 KMainWindow* w; 0568 if(!memberList().isEmpty()) 0569 { 0570 for (int i = 0; i < memberList().size(); ++i) 0571 { 0572 w = memberList().at(i); 0573 KWordQuizApp *a =(KWordQuizApp *) w; 0574 if(a->document()->url().path() == url.path()) 0575 { 0576 if (w->isMinimized()) { 0577 w->setWindowState(w->windowState() & ~Qt::WindowMinimized); 0578 } 0579 w->activateWindow(); 0580 w->raise(); 0581 break; 0582 } 0583 } 0584 } 0585 } 0586 else 0587 { 0588 if (m_tableModel->isEmpty()){ 0589 openDocumentFile(url); 0590 } 0591 else 0592 { 0593 KWordQuizApp *new_window= new KWordQuizApp(); 0594 new_window->show(); 0595 new_window->openDocumentFile(url); 0596 } 0597 } 0598 } 0599 } 0600 0601 void KWordQuizApp::openDocumentFile(const QUrl &url, KEduVocDocument::FileHandlingFlags flags) 0602 { 0603 slotStatusMsg(i18n("Opening file...")); 0604 if (!url.isEmpty()) { 0605 m_tableModel->beginResetModel(); 0606 int result = m_doc->open(url, flags); 0607 if (result == KEduVocDocument::NoError) { 0608 while (m_doc->identifierCount() < 2) { //if we opened a TAB-less CSV, there 0609 m_doc->appendIdentifier(); //may be 0 or 1 identifiers, we need at least 2 0610 } 0611 m_tableModel->endResetModel(); 0612 0613 m_dirWatch->addFile(url.path()); 0614 setWindowTitle(m_doc->url().fileName() + QStringLiteral("[*]")); 0615 setWindowModified(false); 0616 fileOpenRecent->addUrl(url); 0617 slotModeActionGroupTriggered(m_modeActionGroup->checkedAction()); 0618 m_undoStack->clear(); 0619 switch (Prefs::startSession()) { 0620 case Prefs::EnumStartSession::Flashcard: 0621 slotQuizFlash(); 0622 break; 0623 case Prefs::EnumStartSession::MultipleChoice: 0624 slotQuizMultiple(); 0625 break; 0626 case Prefs::EnumStartSession::QA: 0627 slotQuizQA(); 0628 break; 0629 default: 0630 slotQuizEditor(); 0631 break; 0632 } 0633 } 0634 else { 0635 if (result == KEduVocDocument::FileLocked) { 0636 #if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0) 0637 const KMessageBox::ButtonCode userAnswer = KMessageBox::questionTwoActions(this, i18nc("%1 is an error message", "%1\nIf you are sure no other program is using the file you can choose to ignore the lock and open the file anyway.\nDo you want to open the file?", KEduVocDocument::errorDescription(result)), i18n("Open File"), KStandardGuiItem::open(), KStandardGuiItem::cancel()); 0638 #else 0639 const KMessageBox::ButtonCode userAnswer = KMessageBox::questionYesNo(this, i18nc("%1 is an error message", "%1\nIf you are sure no other program is using the file you can choose to ignore the lock and open the file anyway.\nDo you want to open the file?", KEduVocDocument::errorDescription(result))); 0640 #endif 0641 #if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0) 0642 if (userAnswer == KMessageBox::ButtonCode::PrimaryAction) { 0643 #else 0644 if (userAnswer == KMessageBox::Yes) { 0645 #endif 0646 return openDocumentFile(url, KEduVocDocument::FileIgnoreLock); 0647 } 0648 } else { 0649 KMessageBox::error(this, KEduVocDocument::errorDescription(result)); 0650 } 0651 while (m_doc->identifierCount() < 2) { //if we opened a TAB-less CSV, there 0652 m_doc->appendIdentifier(); //may be 0 or 1 identifiers, we need at least 2 0653 } 0654 m_tableModel->endResetModel(); 0655 } 0656 } 0657 slotStatusMsg(i18nc("@info:status ready", "Ready")); 0658 } 0659 0660 KEduVocDocument *KWordQuizApp::document() const 0661 { 0662 return m_doc; 0663 } 0664 0665 void KWordQuizApp::saveOptions() 0666 { 0667 fileOpenRecent->saveEntries(KSharedConfig::openConfig()->group( "Recent Files") ); 0668 Prefs::self()->save(); 0669 } 0670 0671 void KWordQuizApp::readOptions() 0672 { 0673 fileOpenRecent->loadEntries(KSharedConfig::openConfig()->group( "Recent Files") ); 0674 } 0675 0676 void KWordQuizApp::saveProperties(KConfigGroup &_cfg) 0677 { 0678 if(!m_doc->url().fileName().isEmpty() && !m_doc->isModified()) 0679 { 0680 // saving to tempfile not necessary 0681 } 0682 else 0683 { 0684 QUrl url = m_doc->url(); 0685 _cfg.writeEntry("filename", url.url()); 0686 _cfg.writeEntry("modified", m_doc->isModified()); 0687 QString tempname = QTemporaryFile().fileName(); 0688 QString tempurl = QUrl::toPercentEncoding(tempname); 0689 QUrl _url(tempurl); 0690 m_doc->saveAs(_url, KEduVocDocument::Automatic); 0691 } 0692 } 0693 0694 void KWordQuizApp::readProperties(const KConfigGroup &_cfg) 0695 { 0696 QString filename = _cfg.readEntry("filename", ""); 0697 QUrl url(filename); 0698 bool modified = _cfg.readEntry("modified", false); 0699 if(modified) 0700 { 0701 QTemporaryFile tmpfile(filename); 0702 if (tmpfile.open()) { 0703 QUrl _url(QUrl::fromLocalFile(tmpfile.fileName())); 0704 m_doc->open(_url); 0705 m_doc->setModified(); 0706 setWindowTitle(_url.fileName() + QStringLiteral("[*]")); 0707 setWindowModified(true); 0708 } 0709 } 0710 else 0711 { 0712 if(!filename.isEmpty()) 0713 { 0714 m_doc->open(url); 0715 setWindowTitle(url.fileName() + QStringLiteral("[*]")); 0716 setWindowModified(false); 0717 } 0718 } 0719 } 0720 0721 bool KWordQuizApp::queryClose() 0722 { 0723 bool completed=true; 0724 if(m_doc->isModified()) 0725 { 0726 #if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0) 0727 int want_save = KMessageBox::warningTwoActionsCancel(this, i18n("The current document has been modified.\nDo you want to save it?"), QString(), KStandardGuiItem::save(), KStandardGuiItem::discard()); 0728 #else 0729 int want_save = KMessageBox::warningYesNoCancel(this, i18n("The current document has been modified.\nDo you want to save it?"), QString(), KStandardGuiItem::save(), KStandardGuiItem::discard()); 0730 #endif 0731 switch(want_save) 0732 { 0733 case KMessageBox::Cancel: 0734 completed = false; 0735 break; 0736 0737 #if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0) 0738 case KMessageBox::ButtonCode::PrimaryAction: 0739 #else 0740 case KMessageBox::Yes: 0741 #endif 0742 if (m_doc->url().fileName().isEmpty()) 0743 { 0744 completed = saveDocAsFileName(m_doc); 0745 } 0746 else 0747 { 0748 completed = (m_doc->saveAs(m_doc->url(), KEduVocDocument::Automatic) == KEduVocDocument::NoError); 0749 } 0750 0751 break; 0752 0753 #if KWIDGETSADDONS_VERSION >= QT_VERSION_CHECK(5, 100, 0) 0754 case KMessageBox::ButtonCode::SecondaryAction: 0755 #else 0756 case KMessageBox::No: 0757 #endif 0758 completed = true; 0759 break; 0760 0761 default: 0762 completed = false; 0763 break; 0764 } 0765 } 0766 0767 if (completed) 0768 if (m_dirWatch->contains(m_doc->url().toLocalFile())) 0769 m_dirWatch->removeFile(m_doc->url().toLocalFile()); 0770 saveOptions(); 0771 // Close the current document to get rid of its lock file 0772 m_doc->close(); 0773 return completed; 0774 } 0775 0776 0777 void KWordQuizApp::slotFileNew() 0778 { 0779 slotStatusMsg(i18n("Opening a new document window...")); 0780 if (!m_tableModel->isEmpty()){ 0781 KWordQuizApp *new_window= new KWordQuizApp(); 0782 new_window->show(); 0783 } 0784 slotStatusMsg(i18nc("@info:status ready", "Ready")); 0785 } 0786 0787 void KWordQuizApp::slotFileOpen() 0788 { 0789 slotStatusMsg(i18n("Opening file...")); 0790 0791 QCheckBox * cb = new QCheckBox(i18n("&Merge selected files with the current document"), 0); 0792 cb -> setChecked(false); 0793 cb -> setEnabled(false); 0794 0795 QString filter = KEduVocDocument::pattern(KEduVocDocument::Reading); 0796 QPointer<QFileDialog> fd = new QFileDialog(this, i18n("Open Vocabulary Document"), QString(), filter); 0797 fd->setFileMode(QFileDialog::ExistingFiles); 0798 0799 if (fd->exec() == QDialog::Accepted) 0800 { 0801 QList<QUrl> l = fd->selectedUrls(); 0802 bool append = ((cb->isChecked()) && (l.count() >= 1)); 0803 0804 if (append) 0805 { 0806 QList<QUrl>::iterator it; 0807 for(it = l.begin(); it != l.end(); ++it) 0808 { 0809 KEduVocDocument *new_doc = new KEduVocDocument(this); 0810 new_doc->open(*it); 0811 0812 m_doc->merge(new_doc, false); 0813 delete (new_doc); 0814 } 0815 //m_tableModel->reset(); 0816 } 0817 else 0818 { 0819 QList<QUrl>::iterator it; 0820 for(it = l.begin(); it != l.end(); ++it) 0821 { 0822 openUrl(*it); 0823 } 0824 } 0825 } 0826 0827 delete (fd); //deletes cb also 0828 0829 slotStatusMsg(i18nc("@info:status ready", "Ready")); 0830 } 0831 0832 void KWordQuizApp::slotFileOpenRecent(const QUrl &url) 0833 { 0834 slotStatusMsg(i18n("Opening file...")); 0835 fileOpenRecent->setCurrentItem(-1); 0836 openUrl(url); 0837 slotStatusMsg(i18nc("@info:status ready", "Ready")); 0838 } 0839 0840 0841 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0842 void KWordQuizApp::slotFileGHNS(const QList<KNS3::Entry> &entries) 0843 #else 0844 void KWordQuizApp::slotFileGHNS(const QList<KNSCore::Entry> &entries) 0845 #endif 0846 { 0847 QMimeDatabase db; 0848 0849 // list of changed entries 0850 for(const auto &entry : entries) { 0851 // check mime type and if kvtml, open it 0852 for (const QString &file : entry.installedFiles()) { 0853 const QMimeType mimeType = db.mimeTypeForFile(file); 0854 if (mimeType.name() == QLatin1String("application/x-kvtml")) { 0855 KProcess::startDetached(QStringLiteral("kwordquiz"), QStringList() << file); 0856 } 0857 } 0858 } 0859 } 0860 0861 0862 void KWordQuizApp::slotFileSave() 0863 { 0864 bool success = false; 0865 slotStatusMsg(i18n("Saving file...")); 0866 if (m_doc->url().fileName().isEmpty()) { 0867 success = saveDocAsFileName(m_doc); 0868 } 0869 else { 0870 int saveStatus = m_doc->saveAs(m_doc->url(), KEduVocDocument::Automatic); 0871 if (saveStatus == KEduVocDocument::NoError) 0872 success = true; 0873 else 0874 success = saveDocAsFileName(m_doc); 0875 } 0876 if (success) 0877 m_undoStack->setClean(); //emits cleanChanged() 0878 slotStatusMsg(i18nc("@info:status ready", "Ready")); 0879 } 0880 0881 0882 void KWordQuizApp::slotFileSaveAs() 0883 { 0884 slotStatusMsg(i18n("Saving file with a new filename...")); 0885 bool success = saveDocAsFileName(m_doc); 0886 if (success) { 0887 m_undoStack->setClean(); //emits cleanChanged() 0888 setWindowTitle(m_doc->url().fileName() + QStringLiteral("[*]")); //if clean to begin with 0889 setWindowModified(m_doc->isModified()); 0890 } 0891 slotStatusMsg(i18nc("@info:status ready", "Ready")); 0892 } 0893 0894 static QString extractSuffixFromQtPattern(const QString &qtPattern) 0895 { 0896 static const QRegularExpression regexp(".*\\((.*)\\)"); 0897 const QRegularExpressionMatch match = regexp.match(qtPattern); 0898 if (!match.hasMatch()) { 0899 qWarning() << "extractSuffixesFromQtPattern regexp match failed" << qtPattern; 0900 return { QStringLiteral(".report_bug_please") }; 0901 } 0902 return match.captured(1); 0903 } 0904 0905 bool KWordQuizApp::saveDocAsFileName(KEduVocDocument *document) 0906 { 0907 bool success = false; 0908 int result = KEduVocDocument::Unknown; 0909 0910 QString filter = KEduVocDocument::pattern(KEduVocDocument::Writing); 0911 filter.append(QStringLiteral(";;")); 0912 filter.append(i18n("HTML Document") + QStringLiteral(" (*.html)")); 0913 0914 QPointer<QFileDialog> fd = new QFileDialog(this, i18n("Save Vocabulary Document As"), QString(), filter); 0915 fd->setAcceptMode(QFileDialog::AcceptSave); 0916 0917 if (fd->exec() == QDialog::Accepted) { 0918 QUrl url = fd->selectedUrls().at(0); 0919 if (!url.isEmpty()) { 0920 const QString chosenQtFilter = fd->selectedNameFilter(); 0921 const QString chosenFilter = extractSuffixFromQtPattern(chosenQtFilter); 0922 if (!url.fileName().contains(QLatin1Char('.'))) { 0923 qDebug() << "Selected name filter is " << chosenQtFilter << chosenFilter; 0924 if (chosenFilter == QLatin1String("*.csv")) 0925 url.setPath(url.path().append(QStringLiteral(".csv"))); 0926 else if (chosenFilter == QLatin1String("*.kvtml")) 0927 url.setPath(url.path().append(QStringLiteral(".kvtml"))); 0928 else if (chosenFilter == QLatin1String("*.html")) 0929 url.setPath(url.path().append(QStringLiteral(".html"))); 0930 } 0931 0932 if (chosenFilter == QLatin1String("*.html")) { 0933 if (m_tableView->doHtmlExport(url)) 0934 result = KEduVocDocument::NoError; 0935 else 0936 result = KEduVocDocument::FileCannotWrite; 0937 success = false; //export only, do not consider really saved 0938 } 0939 else { 0940 if (m_dirWatch->contains(document->url().toLocalFile())) 0941 m_dirWatch->removeFile(document->url().toLocalFile()); 0942 result = document->saveAs(url, KEduVocDocument::Automatic); 0943 if (result == KEduVocDocument::NoError) { 0944 m_dirWatch->addFile(url.path()); 0945 fileOpenRecent->addUrl(url); 0946 success = true; 0947 } 0948 } 0949 0950 if (result != KEduVocDocument::NoError) { 0951 KMessageBox::error(this, KEduVocDocument::errorDescription(result)); 0952 success = false; 0953 } 0954 } 0955 } 0956 delete(fd); 0957 return success; 0958 } 0959 0960 void KWordQuizApp::slotFileClose() 0961 { 0962 slotStatusMsg(i18n("Closing file...")); 0963 0964 if (memberList().count() > 1) 0965 close(); 0966 else 0967 if (queryClose()) 0968 { 0969 delete m_doc; 0970 initDocument(); 0971 setWindowTitle(m_doc->url().fileName() + "[*]"); 0972 setWindowModified(m_doc->isModified()); 0973 m_tableModel->setDocument(m_doc); 0974 slotQuizEditor(); 0975 slotModeActionGroupTriggered(m_modeActionGroup->actions().at(Prefs::mode() - 1)); 0976 m_tableView ->selectionModel()->setCurrentIndex(m_sortFilterModel->index(0, 0), QItemSelectionModel::SelectCurrent); 0977 m_undoStack->clear(); 0978 } 0979 0980 slotStatusMsg(i18nc("@info:status ready", "Ready")); 0981 } 0982 0983 void KWordQuizApp::slotFilePrint() 0984 { 0985 slotStatusMsg(i18n("Printing...")); 0986 m_tableView->doPrint(); 0987 slotStatusMsg(i18nc("@info:status ready", "Ready")); 0988 } 0989 0990 void KWordQuizApp::slotFilePrintPreview() { 0991 slotStatusMsg(i18n("Showing Preview...")); 0992 m_tableView->doPrintPreview(); 0993 slotStatusMsg(i18nc("@info:status ready", "Ready")); 0994 } 0995 0996 0997 void KWordQuizApp::slotFileQuit() 0998 { 0999 slotStatusMsg(i18nc("@info:status quitting", "Quitting...")); 1000 saveOptions(); 1001 // close the first window, the list makes the next one the first again. 1002 // This ensures that queryClose() is called on each window to ask for closing 1003 KMainWindow* w; 1004 if(!memberList().isEmpty()) 1005 { 1006 for (int i = 0; i < memberList().size(); ++i) 1007 { 1008 w = memberList().at(i); 1009 // only close the window if the closeEvent is accepted. If the user presses Cancel on the saveModified() dialog, 1010 // the window and the application stay open. 1011 if(!w->close()) 1012 break; 1013 // Close the corresponding document to remove its lock file 1014 static_cast<KWordQuizApp *>(w)->document()->close(); 1015 } 1016 } 1017 } 1018 1019 void KWordQuizApp::slotEditCut() 1020 { 1021 slotStatusMsg(i18n("Cutting selection...")); 1022 m_tableView->doEditCut(); 1023 slotStatusMsg(i18nc("@info:status ready", "Ready")); 1024 } 1025 1026 void KWordQuizApp::slotEditCopy() 1027 { 1028 slotStatusMsg(i18n("Copying selection to clipboard...")); 1029 m_tableView->doEditCopy(); 1030 slotStatusMsg(i18nc("@info:status ready", "Ready")); 1031 } 1032 1033 void KWordQuizApp::slotEditPaste() 1034 { 1035 slotStatusMsg(i18n("Inserting clipboard contents...")); 1036 m_tableView->doEditPaste(); 1037 slotStatusMsg(i18nc("@info:status ready", "Ready")); 1038 } 1039 1040 void KWordQuizApp::slotEditClear() 1041 { 1042 slotStatusMsg(i18n("Clearing the selected cells...")); 1043 m_tableView->doEditClear(); 1044 slotStatusMsg(i18nc("@info:status ready", "Ready")); 1045 } 1046 1047 void KWordQuizApp::slotEditInsert() 1048 { 1049 slotStatusMsg(i18n("Inserting rows...")); 1050 m_tableView->doEditInsert(); 1051 slotStatusMsg(i18nc("@info:status ready", "Ready")); 1052 } 1053 1054 void KWordQuizApp::slotEditDelete() 1055 { 1056 slotStatusMsg(i18n("Deleting selected rows...")); 1057 m_tableView->doEditDelete(); 1058 slotStatusMsg(i18nc("@info:status ready", "Ready")); 1059 } 1060 1061 void KWordQuizApp::slotEditMarkBlank() 1062 { 1063 slotStatusMsg(i18n("Marking selected text as a blank...")); 1064 m_tableView->doEditMarkBlank(); 1065 slotStatusMsg(i18nc("@info:status ready", "Ready")); 1066 } 1067 1068 void KWordQuizApp::slotEditUnmarkBlank() 1069 { 1070 slotStatusMsg(i18n("Removing blank markings...")); 1071 m_tableView->doEditUnmarkBlank(); 1072 slotStatusMsg(i18nc("@info:status ready", "Ready")); 1073 } 1074 1075 void KWordQuizApp::slotVocabLanguages() 1076 { 1077 slotStatusMsg(i18n("Setting the column titles of the vocabulary...")); 1078 DlgLanguage* dlg; 1079 dlg = new DlgLanguage(m_tableModel, this); 1080 1081 if (dlg->exec() == QDialog::Accepted) { 1082 KWQCommandIdentifiers *kwqc = new KWQCommandIdentifiers(m_tableView, dlg->columnData()); 1083 m_undoStack->push(kwqc); 1084 } 1085 slotStatusMsg(i18nc("@info:status ready", "Ready")); 1086 } 1087 1088 void KWordQuizApp::slotVocabFont() 1089 { 1090 slotStatusMsg(i18n("Setting the font of the vocabulary...")); 1091 QPointer<QFontDialog> dlg = new QFontDialog(this); 1092 dlg->setObjectName(QStringLiteral("dlg_font")); 1093 dlg->setFont(Prefs::editorFont()); 1094 if (dlg->exec() == QDialog::Accepted) 1095 { 1096 KWQCommandFont *kwqc = new KWQCommandFont(m_tableView, Prefs::editorFont(), dlg->font()); 1097 m_undoStack->push(kwqc); 1098 } 1099 delete dlg; 1100 slotStatusMsg(i18nc("@info:status ready", "Ready")); 1101 } 1102 1103 1104 void KWordQuizApp::slotVocabImage() 1105 { 1106 slotStatusMsg(i18n("Linking an image with the current entry...")); 1107 m_tableView->doVocabImage(); 1108 slotStatusMsg(i18nc("@info:status ready", "Ready")); 1109 } 1110 1111 1112 void KWordQuizApp::slotVocabSound() 1113 { 1114 slotStatusMsg(i18n("Linking a sound with the current entry...")); 1115 m_tableView->doVocabSound(); 1116 slotStatusMsg(i18nc("@info:status ready", "Ready")); 1117 } 1118 1119 1120 void KWordQuizApp::slotVocabAdjustRows() 1121 { 1122 slotStatusMsg(i18n("Adjusting row heights...")); 1123 foreach(const QModelIndex &index, m_tableView->selectionModel()->selectedIndexes()) 1124 m_tableView->adjustRow(index.row()); 1125 slotStatusMsg(i18nc("@info:status ready", "Ready")); 1126 } 1127 1128 1129 void KWordQuizApp::slotVocabShuffle() 1130 { 1131 slotStatusMsg(i18n("Randomizing the vocabulary...")); 1132 m_tableView->doVocabShuffle(); 1133 slotStatusMsg(i18nc("@info:status ready", "Ready")); 1134 } 1135 1136 void KWordQuizApp::slotModeChange() 1137 { 1138 QString newMode; 1139 slotStatusMsg(i18n("Updating mode...")); 1140 if (Prefs::mode() < 5) 1141 newMode = QStringLiteral("mode_%1").arg(QString::number(Prefs::mode() + 1)); 1142 else 1143 newMode = QStringLiteral("mode_1"); 1144 1145 QAction *a = actionCollection()->action(newMode); 1146 a->activate(QAction::Trigger); 1147 slotStatusMsg(i18nc("@info:status ready", "Ready")); 1148 } 1149 1150 1151 void KWordQuizApp::slotQuizEditor() 1152 { 1153 slotStatusMsg(i18n("Starting editor session...")); 1154 m_pageWidget->setCurrentPage(m_editorPage); 1155 slotStatusMsg(i18nc("@info:status ready", "Ready")); 1156 } 1157 1158 void KWordQuizApp::slotQuizFlash() 1159 { 1160 slotStatusMsg(i18n("Starting flashcard session...")); 1161 m_pageWidget->setCurrentPage(m_flashPage); 1162 slotStatusMsg(i18nc("@info:status ready", "Ready")); 1163 } 1164 1165 void KWordQuizApp::slotQuizMultiple() 1166 { 1167 slotStatusMsg(i18n("Starting multiple choice session...")); 1168 m_pageWidget->setCurrentPage(m_multiplePage); 1169 slotStatusMsg(i18nc("@info:status ready", "Ready")); 1170 } 1171 1172 void KWordQuizApp::slotQuizQA() 1173 { 1174 slotStatusMsg(i18n("Starting question & answer session...")); 1175 m_pageWidget->setCurrentPage(m_qaPage); 1176 slotStatusMsg(i18nc("@info:status ready", "Ready")); 1177 } 1178 1179 void KWordQuizApp::slotCurrentPageChanged(KPageWidgetItem *current, KPageWidgetItem *before) 1180 { 1181 Q_UNUSED(before); 1182 delete(m_quiz); 1183 m_quiz = 0; 1184 disconnect(quizCheck, 0, 0, 0); 1185 disconnect(flashKnow, 0, 0, 0); 1186 disconnect(flashDontKnow, 0, 0, 0); 1187 disconnect(quizRestart, 0, 0, 0); 1188 disconnect(actionCollection()->action(QStringLiteral("quiz_audio_play")), 0, 0, 0); 1189 disconnect(quizRepeatErrors, 0, 0, 0); 1190 disconnect(qaHint, 0, 0, 0); 1191 disconnect(qaMarkLastCorrect, 0, 0, 0); 1192 1193 if (current == m_editorPage) { 1194 m_tableView->setFocus(); 1195 m_searchLine->setVisible(Prefs::showSearch()); 1196 } 1197 1198 else if (current == m_flashPage) { 1199 if (Prefs::enableBlanks()) { 1200 if (!m_tableModel->checkSyntax()) 1201 m_pageWidget->setCurrentPage(m_editorPage); 1202 } 1203 m_quiz = new KWQQuizModel(this); 1204 m_quiz->setFilterModel(m_sortFilterModel); 1205 connect(m_quiz, &KWQQuizModel::checkingAnswer, m_tableView, &KWQTableView::slotCheckedAnswer); 1206 m_quiz->setQuizType(Prefs::EnumStartSession::Flashcard); 1207 m_quiz->setQuizMode(Prefs::mode()); 1208 if (m_quiz->init()) 1209 { 1210 connect(quizCheck, SIGNAL(triggered(bool)), m_flashView, SLOT(slotCheck())); 1211 connect(flashKnow, &QAction::triggered, m_flashView, &FlashView::slotKnow); 1212 connect(flashDontKnow, &QAction::triggered, m_flashView, &FlashView::slotDontKnow); 1213 connect(actionCollection()->action(QStringLiteral("quiz_audio_play")), &QAction::triggered, m_flashView, &KWQQuizView::slotAudioPlay); 1214 connect(quizRestart, &QAction::triggered, m_flashView, &KWQQuizView::slotRestart); 1215 connect(quizRepeatErrors, &QAction::triggered, m_flashView, &KWQQuizView::slotRepeat); 1216 connect(this, SIGNAL(settingsChanged()), m_flashView, SLOT(slotApplySettings())); 1217 1218 m_flashView->setQuiz(m_quiz); 1219 m_flashView->init(); 1220 m_flashView->stackedWidget->setCurrentIndex(0); 1221 } 1222 else 1223 { 1224 delete(m_quiz); 1225 m_quiz = 0; 1226 m_flashView->stackedWidget->setCurrentIndex(1); 1227 } 1228 } 1229 1230 else if (current == m_multiplePage) { 1231 if (Prefs::enableBlanks()) { 1232 if (!m_tableModel->checkSyntax()) 1233 m_pageWidget->setCurrentPage(m_editorPage); 1234 } 1235 m_quiz = new KWQQuizModel(this); 1236 m_quiz->setFilterModel(m_sortFilterModel); 1237 connect(m_quiz, &KWQQuizModel::checkingAnswer, m_tableView, &KWQTableView::slotCheckedAnswer); 1238 m_quiz->setQuizType(Prefs::EnumStartSession::MultipleChoice); 1239 m_quiz->setQuizMode(Prefs::mode()); 1240 if (m_quiz->init()) 1241 { 1242 connect(quizCheck, SIGNAL(triggered(bool)), m_multipleView, SLOT(slotCheck())); 1243 connect(quizRestart, &QAction::triggered, m_multipleView, &KWQQuizView::slotRestart); 1244 connect(quizRepeatErrors, &QAction::triggered, m_multipleView, &KWQQuizView::slotRepeat); 1245 connect(this, SIGNAL(settingsChanged()), m_multipleView, SLOT(slotApplySettings())); 1246 1247 m_multipleView->setQuiz(m_quiz); 1248 m_multipleView->init(); 1249 m_multipleView->stackedWidget->setCurrentIndex(0); 1250 } 1251 else 1252 { 1253 delete(m_quiz); 1254 m_quiz = 0; 1255 m_multipleView->stackedWidget->setCurrentIndex(1); 1256 } 1257 } 1258 1259 else if (current == m_qaPage) { 1260 if (Prefs::enableBlanks()) { 1261 if (!m_tableModel->checkSyntax()) 1262 m_pageWidget->setCurrentPage(m_editorPage); 1263 } 1264 m_quiz = new KWQQuizModel(this); 1265 m_quiz->setFilterModel(m_sortFilterModel); 1266 connect(m_quiz, &KWQQuizModel::checkingAnswer, m_tableView, &KWQTableView::slotCheckedAnswer); 1267 m_quiz->setQuizType(Prefs::EnumStartSession::QA); 1268 m_quiz->setQuizMode(Prefs::mode()); 1269 if (m_quiz->init()) 1270 { 1271 connect(quizCheck, SIGNAL(triggered(bool)), m_qaView, SLOT(slotCheck())); 1272 connect(qaHint, &QAction::triggered, m_qaView, &QAView::slotHint); 1273 connect(qaMarkLastCorrect, &QAction::triggered, m_qaView, &QAView::slotMarkLastCorrect); 1274 connect(quizRestart, &QAction::triggered, m_qaView, &KWQQuizView::slotRestart); 1275 connect(actionCollection()->action(QStringLiteral("quiz_audio_play")), &QAction::triggered, m_qaView, &KWQQuizView::slotAudioPlay); 1276 connect(quizRepeatErrors, &QAction::triggered, m_qaView, &KWQQuizView::slotRepeat); 1277 connect(this, SIGNAL(settingsChanged()), m_qaView, SLOT(slotApplySettings())); 1278 1279 m_qaView->setQuiz(m_quiz); 1280 m_qaView->init(); 1281 m_qaView->stackedWidget->setCurrentIndex(0); 1282 } 1283 else 1284 { 1285 delete(m_quiz); 1286 m_quiz = 0; 1287 m_qaView->stackedWidget->setCurrentIndex(1); 1288 } 1289 } 1290 1291 updateActions(); 1292 } 1293 1294 /** Configure notifications */ 1295 void KWordQuizApp::slotConfigureNotifications( ) 1296 { 1297 KNotifyConfigWidget::configure(this); 1298 } 1299 1300 /** Configure kwordquiz */ 1301 void KWordQuizApp::slotConfigure() 1302 { 1303 if (KWordQuizPrefs::showDialog(QStringLiteral("settings"))) 1304 return; 1305 1306 //KConfigDialog didn't find an instance of this dialog, so lets create it : 1307 KWordQuizPrefs* dialog = new KWordQuizPrefs(this, QStringLiteral("settings"), Prefs::self(), actionCollection()); 1308 connect(dialog, &KConfigDialog::settingsChanged, this, &KWordQuizApp::slotApplyPreferences); 1309 dialog->show(); 1310 } 1311 1312 void KWordQuizApp::slotApplyPreferences() 1313 { 1314 editMarkBlank->setEnabled(Prefs::enableBlanks()); 1315 editUnmarkBlank->setEnabled(Prefs::enableBlanks()); 1316 m_tableView->reset(); 1317 updateSpecialCharIcons(); 1318 Q_EMIT settingsChanged(); 1319 } 1320 1321 void KWordQuizApp::updateSpecialCharIcons() 1322 { 1323 for (int i = 0; i < 9; i++){ 1324 QAction * a = actionCollection()->action(QStringLiteral("char_%1").arg(QString::number(i + 1))); 1325 a->setIcon(charIcon(Prefs::specialCharacters()[i])); 1326 a->setIconText(i18n("Insert %1", Prefs::specialCharacters()[i])); 1327 a->setWhatsThis(i18n("Inserts the character %1", Prefs::specialCharacters()[i])); 1328 a->setToolTip(a->whatsThis()); 1329 a->setStatusTip(a->whatsThis()); 1330 } 1331 } 1332 1333 QIcon KWordQuizApp::charIcon(const QChar & c) 1334 { 1335 QRect r(4, 4, 120, 120); 1336 1337 ///A font to draw the character with 1338 QFont font(QStringLiteral("sans")); 1339 font.setPixelSize(100); 1340 font.setWeight(QFont::Bold); 1341 1342 ///Create the pixmap 1343 QPixmap pm(128, 128); 1344 pm.fill(Qt::white); 1345 QPainter p; 1346 p.begin(&pm); 1347 p.setFont(font); 1348 p.setPen(Qt::blue); 1349 p.drawText(r, Qt::AlignCenter, (QString) c); 1350 p.end(); 1351 1352 ///Create transparency mask 1353 QBitmap bm(128, 128); 1354 bm.fill(Qt::color0); 1355 QPainter b; 1356 b.begin(&bm); 1357 b.setFont(font); 1358 b.setPen(Qt::color1); 1359 b.drawText(r, Qt::AlignCenter, (QString) c); 1360 b.end(); 1361 1362 ///Mask the pixmap 1363 pm.setMask(bm); 1364 1365 return QIcon(pm); 1366 } 1367 1368 void KWordQuizApp::slotStatusMsg(const QString &text) 1369 { 1370 //statusBar()->clearMessage(); 1371 statusBar()->showMessage(text); 1372 } 1373 1374 1375 void KWordQuizApp::slotModeActionGroupTriggered(QAction *act) 1376 { 1377 if (m_quiz != 0) 1378 if (KMessageBox::warningContinueCancel(this, i18n("This will restart your quiz. Do you wish to continue?"), QString(), KStandardGuiItem::cont(), KStandardGuiItem::cancel(), QStringLiteral("askModeQuiz")) 1379 != KMessageBox::Continue) 1380 { 1381 m_modeActionGroup->actions()[0]->setChecked(Prefs::mode() == 1); 1382 m_modeActionGroup->actions()[1]->setChecked(Prefs::mode() == 2); 1383 m_modeActionGroup->actions()[2]->setChecked(Prefs::mode() == 3); 1384 m_modeActionGroup->actions()[3]->setChecked(Prefs::mode() == 4); 1385 m_modeActionGroup->actions()[4]->setChecked(Prefs::mode() == 5); 1386 return; 1387 } 1388 1389 act->setChecked(true); 1390 1391 QString s1 = m_tableModel->headerData(0, Qt::Horizontal, Qt::DisplayRole).toString(); 1392 QString s2 = m_tableModel->headerData(1, Qt::Horizontal, Qt::DisplayRole).toString(); 1393 1394 m_modeActionGroup->actions()[0]->setText(i18n("&1 %1 -> %2 In Order", s1, s2)); 1395 m_modeActionGroup->actions()[1]->setText(i18n("&2 %1 -> %2 In Order", s2, s1)); 1396 m_modeActionGroup->actions()[2]->setText(i18n("&3 %1 -> %2 Randomly", s1, s2)); 1397 m_modeActionGroup->actions()[3]->setText(i18n("&4 %1 -> %2 Randomly", s2, s1)); 1398 m_modeActionGroup->actions()[4]->setText(i18n("&5 %1 <-> %2 Randomly", s1, s2)); 1399 1400 Prefs::setMode(act->data().toInt()); 1401 m_modeActionMenu->setIcon(QIcon::fromTheme(QStringLiteral("mode") + QString::number(Prefs::mode()))); 1402 1403 switch (Prefs::mode()){ 1404 case 1: 1405 m_statusLabel->setText(i18n("%1 -> %2 In Order", s1, s2)); 1406 break; 1407 case 2: 1408 m_statusLabel->setText(i18n("%1 -> %2 In Order", s2, s1)); 1409 break; 1410 case 3: 1411 m_statusLabel->setText(i18n("%1 -> %2 Randomly", s1, s2)); 1412 break; 1413 case 4: 1414 m_statusLabel->setText(i18n("%1 -> %2 Randomly", s2, s1)); 1415 break; 1416 case 5: 1417 m_statusLabel->setText(i18n("%1 <-> %2 Randomly", s1, s2)); 1418 break; 1419 } 1420 1421 if (m_quiz !=0) 1422 slotCurrentPageChanged(m_pageWidget->currentPage(), m_pageWidget->currentPage()); 1423 } 1424 1425 1426 void KWordQuizApp::slotInsertChar( int i ) 1427 { 1428 if (m_pageWidget->currentPage() == m_qaPage) 1429 m_qaView->slotSpecChar(Prefs::specialCharacters()[i - 1]); 1430 else 1431 if (m_pageWidget->currentPage() == m_editorPage) { 1432 m_tableView->slotSpecChar(Prefs::specialCharacters()[i - 1]); 1433 } 1434 } 1435 1436 1437 void KWordQuizApp::updateActions() 1438 { 1439 bool fEdit = (m_pageWidget->currentPage() == m_editorPage); 1440 bool fQuiz = !fEdit && (m_quiz != 0); 1441 1442 fileSave->setEnabled(fEdit); 1443 fileSaveAs->setEnabled(fEdit); 1444 filePrint->setEnabled(fEdit); 1445 filePrintPreview->setEnabled(fEdit); 1446 1447 editCopy->setEnabled(fEdit); 1448 editCut->setEnabled(fEdit); 1449 editPaste->setEnabled(fEdit); 1450 editClear->setEnabled(fEdit); 1451 editInsert->setEnabled(fEdit); 1452 editDelete->setEnabled(fEdit); 1453 editMarkBlank->setEnabled(fEdit && Prefs::enableBlanks()); 1454 editUnmarkBlank->setEnabled(fEdit && Prefs::enableBlanks()); 1455 1456 vocabLanguages->setEnabled(fEdit); 1457 vocabFont->setEnabled(fEdit); 1458 actionCollection()->action(QStringLiteral("vocab_image"))->setEnabled(fEdit); 1459 actionCollection()->action(QStringLiteral("vocab_sound"))->setEnabled(fEdit); 1460 vocabAdjustRows->setEnabled(fEdit); 1461 vocabShuffle->setEnabled(fEdit); 1462 1463 quizCheck->setEnabled(fQuiz); 1464 quizRestart->setEnabled(fQuiz); 1465 quizRepeatErrors->setEnabled(false); 1466 quizExportErrors->setEnabled(false); 1467 1468 flashKnow->setEnabled((m_pageWidget->currentPage() == m_flashPage) && fQuiz); 1469 flashDontKnow->setEnabled((m_pageWidget->currentPage() == m_flashPage) && fQuiz); 1470 1471 qaHint->setEnabled((m_pageWidget->currentPage() == m_qaPage) && fQuiz); 1472 qaMarkLastCorrect->setVisible((m_pageWidget->currentPage() == m_qaPage) && fQuiz); 1473 actionCollection()->action(QStringLiteral("quiz_audio_play"))->setEnabled(false); 1474 1475 quizOpt1->setEnabled((m_pageWidget->currentPage() == m_multiplePage) && fQuiz); 1476 quizOpt2->setEnabled((m_pageWidget->currentPage() == m_multiplePage) && fQuiz); 1477 quizOpt3->setEnabled((m_pageWidget->currentPage() == m_multiplePage) && fQuiz); 1478 1479 configShowSearchBar->setEnabled(fEdit); 1480 1481 addToolBar(Qt::RightToolBarArea, toolBar(QStringLiteral("quizToolBar"))); 1482 toolBar(QStringLiteral("quizToolBar"))->setHidden(fEdit); 1483 } 1484 1485 1486 void KWordQuizApp::slotConfigShowSearch() 1487 { 1488 if (m_searchLine) { 1489 m_searchLine->setVisible(m_searchLine->isHidden()); 1490 Prefs::setShowSearch(m_searchLine->isVisible()); 1491 } 1492 } 1493 1494 1495 void KWordQuizApp::slotCleanChanged(bool clean) 1496 { 1497 m_doc->setModified(!clean); 1498 setWindowTitle(m_doc->url().fileName() + "[*]"); 1499 setWindowModified(m_doc->isModified()); 1500 } 1501 1502 1503 void KWordQuizApp::slotUndoTextChanged(const QString & undoText) 1504 { 1505 Q_UNUSED(undoText); 1506 editUndo->setWhatsThis(editUndo->text()); 1507 editUndo->setStatusTip(editUndo->text()); 1508 1509 slotModeActionGroupTriggered(m_modeActionGroup->actions().at(Prefs::mode() - 1)); 1510 } 1511 1512 1513 void KWordQuizApp::slotRedoTextChanged(const QString &redoText) 1514 { 1515 Q_UNUSED(redoText); 1516 editRedo->setWhatsThis(editRedo->text()); 1517 editRedo->setStatusTip(editRedo->text()); 1518 1519 slotModeActionGroupTriggered(m_modeActionGroup->actions().at(Prefs::mode() - 1)); 1520 } 1521 1522 void KWordQuizApp::slotCreateErrorListDocument() 1523 { 1524 if (m_quiz) { 1525 KEduVocDocument *errorDoc = new KEduVocDocument(this); 1526 errorDoc->appendIdentifier(); 1527 errorDoc->identifier(0).setName(m_tableModel->headerData(0, Qt::Horizontal, Qt::DisplayRole).toString()); 1528 errorDoc->appendIdentifier(); 1529 errorDoc->identifier(1).setName(m_tableModel->headerData(1, Qt::Horizontal, Qt::DisplayRole).toString()); 1530 1531 const auto errors{m_quiz->errorList()}; 1532 for (int item : errors) { 1533 KEduVocExpression *errorExpr = new KEduVocExpression(); 1534 errorDoc->lesson()->appendEntry(errorExpr); 1535 errorExpr->setTranslation(0, m_quiz->data(m_quiz->index(item, 0), Qt::DisplayRole).toString()); 1536 errorExpr->setTranslation(1, m_quiz->data(m_quiz->index(item, 1), Qt::DisplayRole).toString()); 1537 } 1538 saveDocAsFileName(errorDoc); 1539 if (m_dirWatch->contains(errorDoc->url().toLocalFile())) 1540 m_dirWatch->removeFile(errorDoc->url().toLocalFile()); 1541 } 1542 } 1543 1544 void KWordQuizApp::slotTableContextMenuRequested(const QPoint & pos) 1545 { 1546 QMenu *popup = static_cast<QMenu*>(guiFactory()->container(QStringLiteral("editor_popup"),this)); 1547 QAction *a; 1548 int column = m_tableView->currentIndex().column(); 1549 QString currentLayout = QLatin1String(""); 1550 currentLayout = m_tableModel->headerData(column, Qt::Horizontal, KWQTableModel::KeyboardLayoutRole).toString(); 1551 1552 // keyboard layout 1553 // try to talk to kxbk - get a list of keyboard layouts 1554 QDBusInterface kxbk(QStringLiteral("org.kde.keyboard"), QStringLiteral("/Layouts"), QStringLiteral("org.kde.KeyboardLayouts")); 1555 QDBusReply<QStringList> reply = kxbk.call(QStringLiteral("getLayoutsList")); 1556 if (reply.isValid()) { 1557 const QStringList layouts = reply; 1558 //layouts.prepend(QString()); 1559 QMenu *m = vocabLayouts->menu(); 1560 m->clear(); 1561 for (const QString &s : layouts) { 1562 a = m->addAction(s); 1563 a->setData(s); 1564 a->setCheckable(true); 1565 a->setActionGroup(m_layoutActionGroup); 1566 if (s == currentLayout) 1567 a->setChecked(true); 1568 } 1569 } else { 1570 qDebug() << "kxkb dbus error"; 1571 } 1572 1573 popup->exec(m_tableView->viewport()->mapToGlobal(pos)); 1574 } 1575 1576 void KWordQuizApp::slotLayoutActionGroupTriggered(QAction *act) 1577 { 1578 int column = m_tableView->currentIndex().column(); 1579 m_tableModel->setHeaderData(column, Qt::Horizontal, act->data().toString(), KWQTableModel::KeyboardLayoutRole); 1580 }