moved kdeaccessibility kdeaddons kdeadmin kdeartwork kdebindings kdeedu kdegames...
[kdeedu.git] / kwordquiz / src / kwordquiz.cpp
blob35c08dee90fb0cff69941b6c7becfb5d32e1b10e
1 /***************************************************************************
2 kwordquiz.cpp - description
3 -------------------
4 begin : Wed Jul 24 20:12:30 PDT 2002
5 copyright : (C) 2002 by Peter Hedlund
6 email : peter@peterandlinda.com
7 ***************************************************************************/
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
18 // include files for QT
19 #include <qpainter.h>
20 #include <qbitmap.h>
21 #include <qcheckbox.h>
23 // include files for KDE
24 #include <kmessagebox.h>
25 #include <kfiledialog.h>
26 #include <kstatusbar.h>
27 #include <klocale.h>
28 #include <kedittoolbar.h>
29 #include <kstandarddirs.h> //locate
30 #include <kfontdialog.h>
31 #include <kpopupmenu.h>
32 #include <knotifydialog.h>
33 #include <kiconloader.h>
34 //#include <keduvocdata.h>
35 #include <kdebug.h>
37 // application specific includes
38 #include "kwordquiz.h"
39 #include "kwordquizdoc.h"
40 #include "dlglanguage.h"
41 #include "kwordquizprefs.h"
42 #include "qaview.h"
43 #include "flashview.h"
44 #include "multipleview.h"
45 #include "wqprintdialogpage.h"
46 #include "prefs.h"
48 #define ID_STATUS_MSG 1
49 #define ID_STATUS_MSG_MODE 2
50 #define ID_STATUS_MSG_SCORE 3
52 #define ID_MODE_1 1
54 #define ID_MENU_QUIZ 1001
56 KWordQuizApp::KWordQuizApp(QWidget* , const char* name):KMainWindow(0, name)
59 ///////////////////////////////////////////////////////////////////
60 // call inits to invoke all other construction parts
61 initStatusBar();
62 initActions();
63 initDocument();
65 readOptions();
67 initView();
69 m_dirWatch = KDirWatch::self();
70 m_quizType = WQQuiz::qtEditor;
71 m_quiz = 0;
72 m_flashView = 0;
73 m_multipleView = 0;
74 m_qaView = 0;
76 slotQuizEditor();
77 slotUndoChange(i18n("Cannot &Undo"), false);
78 updateMode(Prefs::mode());
80 m_prefDialog = 0;
82 editMarkBlank->setEnabled(Prefs::enableBlanks());
83 editUnmarkBlank->setEnabled(Prefs::enableBlanks());
85 if (Prefs::firstRun())
87 fileOpenRecent->addURL( locate("data", "kwordquiz/examples/example.kvtml"));
88 fileOpenRecent->addURL( locate("data", "kwordquiz/examples/french_verbs.kvtml"));
89 fileOpenRecent->addURL( locate("data", "kwordquiz/examples/fill_in_the_blank.kvtml"));
90 fileOpenRecent->addURL( locate("data", "kwordquiz/examples/us_states_and_capitals.kvtml"));
91 Prefs::setFirstRun(false);
95 KWordQuizApp::~KWordQuizApp()
100 void KWordQuizApp::initActions()
102 KAction* configToolbar;
103 KAction* configNotifications;
104 KAction* configApp;
106 fileNew = KStdAction::openNew(this, SLOT(slotFileNew()), actionCollection());
107 fileNew->setWhatsThis(i18n("Creates a new blank vocabulary document"));
108 fileNew->setToolTip(fileNew->whatsThis());
110 fileOpen = KStdAction::open(this, SLOT(slotFileOpen()), actionCollection());
111 fileOpen->setWhatsThis(i18n("Opens an existing vocabulary document"));
112 fileOpen->setToolTip(fileOpen->whatsThis());
114 fileOpenRecent = KStdAction::openRecent(this, SLOT(slotFileOpenRecent(const KURL&)), actionCollection());
116 fileSave = KStdAction::save(this, SLOT(slotFileSave()), actionCollection());
117 fileSave->setWhatsThis(i18n("Saves the active vocabulary document"));
118 fileSave->setToolTip(fileSave->whatsThis());
120 fileSaveAs = KStdAction::saveAs(this, SLOT(slotFileSaveAs()), actionCollection());
121 fileSaveAs->setWhatsThis(i18n("Saves the active vocabulary document with a different name"));
122 fileSaveAs->setToolTip(fileSaveAs->whatsThis());
124 fileClose = KStdAction::close(this, SLOT(slotFileClose()), actionCollection());
125 fileClose->setWhatsThis(i18n("Closes the active vocabulary document"));
126 fileClose->setToolTip(fileClose->whatsThis());
128 filePrint = KStdAction::print(this, SLOT(slotFilePrint()), actionCollection());
129 filePrint->setWhatsThis(i18n("Prints the active vocabulary document"));
130 filePrint->setToolTip(filePrint->whatsThis());
132 fileQuit = KStdAction::quit(this, SLOT(slotFileQuit()), actionCollection());
133 fileQuit->setWhatsThis(i18n("Quits KWordQuiz"));
134 fileQuit->setToolTip(fileQuit->whatsThis());
136 editUndo = KStdAction::undo(this, SLOT(slotEditUndo()), actionCollection());
137 editUndo->setWhatsThis(i18n("Undoes the last command"));
138 editUndo->setToolTip(editUndo->whatsThis());
140 editCut = KStdAction::cut(this, SLOT(slotEditCut()), actionCollection());
141 editCut->setWhatsThis(i18n("Cuts the text from the selected cells and places it on the clipboard"));
142 editCut->setToolTip(editCut->whatsThis());
144 editCopy = KStdAction::copy(this, SLOT(slotEditCopy()), actionCollection());
145 editCopy->setWhatsThis(i18n("Copies the text from the selected cells and places it on the clipboard"));
146 editCopy->setToolTip(editCopy->whatsThis());
148 editPaste = KStdAction::paste(this, SLOT(slotEditPaste()), actionCollection());
149 editPaste->setWhatsThis(i18n("Pastes previously cut or copied text from the clipboard into the selected cells"));
150 editPaste->setToolTip(editPaste->whatsThis());
152 editClear = KStdAction::clear(this, SLOT(slotEditClear()), actionCollection());
153 editClear->setWhatsThis(i18n("Clears the content of the selected cells"));
154 editClear->setToolTip(editClear->whatsThis());
156 editInsert = new KAction(i18n("&Insert Row"), "insert_table_row", "CTRL+I", this, SLOT(slotEditInsert()), actionCollection(),"edit_insert");
157 editInsert->setWhatsThis(i18n("Inserts a new row above the current row"));
158 editInsert->setToolTip(editInsert->whatsThis());
160 editDelete = new KAction(i18n("&Delete Row"), "delete_table_row", "CTRL+K", this, SLOT(slotEditDelete()), actionCollection(),"edit_delete");
161 editDelete->setWhatsThis(i18n("Deletes the selected row(s)"));
162 editDelete->setToolTip(editDelete->whatsThis());
164 editMarkBlank = new KAction(i18n("&Mark as Blank"), "markasblank", "CTRL+M", this, SLOT(slotEditMarkBlank()), actionCollection(),"edit_mark_blank");
165 editMarkBlank->setWhatsThis(i18n("Marks the current or selected word as a blank for Fill-in-the-blank"));
166 editMarkBlank->setToolTip(editMarkBlank->whatsThis());
168 editUnmarkBlank = new KAction(i18n("&Unmark Blanks"), "unmarkasblank", 0, this, SLOT(slotEditUnmarkBlank()), actionCollection(),"edit_unmark_blank");
169 editUnmarkBlank->setWhatsThis(i18n("Removes blanks from the current or selected word"));
170 editUnmarkBlank->setToolTip(editUnmarkBlank->whatsThis());
172 //@todo implement editFind = KStdAction::find(this, SLOT(slotEditFind()), actionCollection());
174 vocabLanguages = new KAction(i18n("&Column Titles..."), "languages", "CTRL+L", this, SLOT(slotVocabLanguages()), actionCollection(),"vocab_languages");
175 vocabLanguages->setWhatsThis(i18n("Defines the column titles for the active vocabulary"));
176 vocabLanguages->setToolTip(vocabLanguages->whatsThis());
178 vocabFont = new KAction(i18n("&Font..."), "fonts", 0, this, SLOT(slotVocabFont()), actionCollection(),"vocab_font");
179 vocabFont->setWhatsThis(i18n("Defines the font used by the editor"));
180 vocabFont->setToolTip(vocabFont->whatsThis());
182 //@todo implement vocabKeyboard = new KAction(i18n("&Keyboard..."), "kxkb", 0, this, SLOT(slotVocabKeyboard()), actionCollection(),"vocab_keyboard");
184 vocabRC = new KAction(i18n("&Rows/Columns..."), "rowcol", 0, this, SLOT(slotVocabRC()), actionCollection(),"vocab_rc");
185 vocabRC->setWhatsThis(i18n("Defines the number of rows, row heights, and column widths for the active vocabulary"));
186 vocabRC->setToolTip(vocabRC->whatsThis());
188 vocabSort = new KAction(i18n("&Sort..."), "sort_incr", 0, this, SLOT(slotVocabSort()), actionCollection(),"vocab_sort");
189 vocabSort->setWhatsThis(i18n("Sorts the vocabulary in ascending or descending order based on the left or right column"));
190 vocabSort->setToolTip(vocabSort->whatsThis());
192 vocabShuffle = new KAction(i18n("Sh&uffle"), "shuffle", 0, this, SLOT(slotVocabShuffle()), actionCollection(),"vocab_shuffle");
193 vocabShuffle->setWhatsThis(i18n("Shuffles the entries of the active vocabulary"));
194 vocabShuffle->setToolTip(vocabShuffle->whatsThis());
196 mode = new KToolBarPopupAction(i18n("Change Mode"), "mode1", 0, this, SLOT(slotMode0()), actionCollection(),"mode_0");
197 mode->setWhatsThis(i18n("Changes the mode used in quiz sessions"));
198 mode->setToolTip(mode->whatsThis());
200 KPopupMenu *popup = mode->popupMenu();
201 popup->clear();
202 popup->insertItem(KGlobal::iconLoader()->loadIconSet("mode1", KIcon::Toolbar), "", this, SLOT(slotMode1()), 0, 0);
203 popup->insertItem(KGlobal::iconLoader()->loadIconSet("mode2", KIcon::Toolbar), "", this, SLOT(slotMode2()), 0, 1);
204 popup->insertItem(KGlobal::iconLoader()->loadIconSet("mode3", KIcon::Toolbar), "", this, SLOT(slotMode3()), 0, 2);
205 popup->insertItem(KGlobal::iconLoader()->loadIconSet("mode4", KIcon::Toolbar), "", this, SLOT(slotMode4()), 0, 3);
206 popup->insertItem(KGlobal::iconLoader()->loadIconSet("mode5", KIcon::Toolbar), "", this, SLOT(slotMode5()), 0, 4);
208 mode1 = new KToggleAction("", "mode1", 0, this, SLOT(slotMode1()), actionCollection(),"mode_1");
209 mode2 = new KToggleAction("", "mode2", 0, this, SLOT(slotMode2()), actionCollection(),"mode_2");
210 mode3 = new KToggleAction("", "mode3", 0, this, SLOT(slotMode3()), actionCollection(),"mode_3");
211 mode4 = new KToggleAction("", "mode4", 0, this, SLOT(slotMode4()), actionCollection(),"mode_4");
212 mode5 = new KToggleAction("", "mode5", 0, this, SLOT(slotMode5()), actionCollection(),"mode_5");
213 mode1->setWhatsThis(i18n("Selects this mode"));
214 mode2->setWhatsThis(i18n("Selects this mode"));
215 mode3->setWhatsThis(i18n("Selects this mode"));
216 mode4->setWhatsThis(i18n("Selects this mode"));
217 mode5->setWhatsThis(i18n("Selects this mode"));
218 mode1->setToolTip(mode1->whatsThis());
219 mode2->setToolTip(mode2->whatsThis());
220 mode3->setToolTip(mode3->whatsThis());
221 mode4->setToolTip(mode4->whatsThis());
222 mode5->setToolTip(mode5->whatsThis());
224 quizEditor = new KAction(i18n("&Editor"), "editor", "F6", this, SLOT(slotQuizEditor()), actionCollection(),"quiz_editor");
225 quizEditor->setWhatsThis(i18n("Activates the vocabulary editor"));
226 quizEditor->setToolTip(quizEditor->whatsThis());
228 quizFlash = new KAction(i18n("&Flashcard"), "flash", "F7", this, SLOT(slotQuizFlash()), actionCollection(),"quiz_flash");
229 quizFlash->setWhatsThis(i18n("Starts a flashcard session using the active vocabulary"));
230 quizFlash->setToolTip(quizFlash->whatsThis());
232 quizMultiple = new KAction(i18n("&Multiple Choice"), "multiple", "F8", this, SLOT(slotQuizMultiple()), actionCollection(),"quiz_multiple");
233 quizMultiple->setWhatsThis(i18n("Starts a multiple choice session using the active vocabulary"));
234 quizMultiple->setToolTip(quizMultiple->whatsThis());
236 quizQA = new KAction(i18n("&Question && Answer"), "qa", "F9", this, SLOT(slotQuizQA()), actionCollection(),"quiz_qa");
237 quizQA->setWhatsThis(i18n("Starts a question and answer session using the active vocabulary"));
238 quizQA->setToolTip(quizQA->whatsThis());
240 quizCheck = new KAction(i18n("&Check"), "check", "Return", this, 0, actionCollection(),"quiz_check");
241 quizCheck->setWhatsThis(i18n("Checks your answer to this question"));
242 quizCheck->setToolTip(quizCheck->whatsThis());
244 flashKnow = new KAction(i18n("I &Know"), "know", "K", this, 0, actionCollection(),"flash_know");
245 flashKnow->setWhatsThis(i18n("Counts this card as correct and shows the next card"));
246 flashKnow->setToolTip(flashKnow->whatsThis());
248 flashDontKnow = new KAction(i18n("I &Do Not Know"), "dontknow", "D", this, 0, actionCollection(),"flash_dont_know");
249 flashDontKnow->setWhatsThis(i18n("Counts this card as incorrect and shows the next card"));
250 flashDontKnow->setToolTip(flashDontKnow->whatsThis());
252 qaHint = new KAction(i18n("&Hint"), "hint", "CTRL+H", this, 0, actionCollection(),"qa_hint");
253 qaHint->setWhatsThis(i18n("Gets the next correct letter of the answer"));
254 qaHint->setToolTip(qaHint->whatsThis());
256 quizRestart = new KAction(i18n("&Restart"), "restart.png", "CTRL+R", this, 0, actionCollection(), "quiz_restart");
257 quizRestart->setWhatsThis(i18n("Restarts the quiz session from the beginning"));
258 quizRestart->setToolTip(quizRestart->whatsThis());
260 quizRepeatErrors = new KAction(i18n("Repeat &Errors"), "repeat", "CTRL+E", this, 0, actionCollection(),"quiz_repeat_errors");
261 quizRepeatErrors->setWhatsThis(i18n("Repeats all incorrectly answered questions"));
262 quizRepeatErrors->setToolTip(quizRepeatErrors->whatsThis());
264 configNotifications = KStdAction::configureNotifications(this, SLOT(slotConfigureNotifications()), actionCollection());
265 configNotifications->setWhatsThis(i18n("Configures sound and other notifications for certain events"));
266 configNotifications->setToolTip(configNotifications->whatsThis());
268 configApp = KStdAction::preferences(this, SLOT( slotConfigure()), actionCollection());
269 configApp->setWhatsThis(i18n("Specifies preferences for the vocabulary editor and quiz sessions"));
270 configApp->setToolTip(configApp->whatsThis());
272 charMapper = new QSignalMapper(this);
273 connect(charMapper, SIGNAL(mapped(int)), this, SLOT(slotInsertChar(int)));
275 specialChar1 = new KAction(i18n("Special Character 1"), "", "CTRL+1", charMapper, SLOT(map()), actionCollection(), "char_1") ;
276 specialChar2 = new KAction(i18n("Special Character 2"), 0, "CTRL+2", charMapper, SLOT(map()), actionCollection(), "char_2") ;
277 specialChar3 = new KAction(i18n("Special Character 3"), 0, "CTRL+3", charMapper, SLOT(map()), actionCollection(), "char_3") ;
278 specialChar4 = new KAction(i18n("Special Character 4"), 0, "CTRL+4", charMapper, SLOT(map()), actionCollection(), "char_4") ;
279 specialChar5 = new KAction(i18n("Special Character 5"), 0, "CTRL+5", charMapper, SLOT(map()), actionCollection(), "char_5") ;
280 specialChar6 = new KAction(i18n("Special Character 6"), 0, "CTRL+6", charMapper, SLOT(map()), actionCollection(), "char_6") ;
281 specialChar7 = new KAction(i18n("Special Character 7"), 0, "CTRL+7", charMapper, SLOT(map()), actionCollection(), "char_7") ;
282 specialChar8 = new KAction(i18n("Special Character 8"), 0, "CTRL+8", charMapper, SLOT(map()), actionCollection(), "char_8") ;
283 specialChar9 = new KAction(i18n("Special Character 9"), 0, "CTRL+9", charMapper, SLOT(map()), actionCollection(), "char_9") ;
285 charMapper->setMapping(specialChar1, 1);
286 charMapper->setMapping(specialChar2, 2);
287 charMapper->setMapping(specialChar3, 3);
288 charMapper->setMapping(specialChar4, 4);
289 charMapper->setMapping(specialChar5, 5);
290 charMapper->setMapping(specialChar6, 6);
291 charMapper->setMapping(specialChar7, 7);
292 charMapper->setMapping(specialChar8, 8);
293 charMapper->setMapping(specialChar9, 9);
295 actionCollection()->setHighlightingEnabled(true);
296 connect(actionCollection(), SIGNAL(actionStatusText(const QString &)), this, SLOT(slotStatusMsg(const QString &)));
297 connect(actionCollection(), SIGNAL(actionHighlighted(KAction *, bool)), this, SLOT(slotActionHighlighted(KAction *, bool)));
298 updateSpecialCharIcons();
300 if (!initialGeometrySet())
301 resize( QSize(650, 500).expandedTo(minimumSizeHint()));
302 setupGUI(ToolBar | Keys | StatusBar | Create);
303 setAutoSaveSettings();
305 configToolbar = actionCollection()->action("options_configure_toolbars");
306 configToolbar->setWhatsThis(i18n("Toggles display of the toolbars"));
307 configToolbar->setToolTip(configToolbar->whatsThis());
310 void KWordQuizApp::initStatusBar()
312 statusBar()->insertFixedItem("", ID_STATUS_MSG_MODE, true);
313 statusBar()->setItemFixed(ID_STATUS_MSG_MODE, 250);
314 statusBar()->setItemAlignment(ID_STATUS_MSG_MODE, AlignLeft|AlignVCenter);
317 void KWordQuizApp::initDocument()
319 doc = new KWordQuizDoc(this);
320 doc->newDocument();
323 void KWordQuizApp::initView()
325 m_editView = new KWordQuizView(this);
326 doc->addView(m_editView);
327 setCentralWidget(m_editView);
328 setCaption(doc->URL().fileName(),false);
329 m_editView->setFont(Prefs::editorFont());
330 connect(m_editView, SIGNAL(undoChange(const QString&, bool )), this, SLOT(slotUndoChange(const QString&, bool)));
331 connect(m_editView, SIGNAL(contextMenuRequested(int, int, const QPoint &)), this, SLOT(slotContextMenuRequested(int, int, const QPoint& )));
334 void KWordQuizApp::openURL(const KURL& url)
336 if(!url.isEmpty()) {
337 if (m_dirWatch->contains(url.path()))
339 KMainWindow* w;
340 if(memberList)
342 for(w=memberList->first(); w!=0; w=memberList->next())
344 KWordQuizApp *a =(KWordQuizApp *) w;
345 if(a->doc ->URL().path() == url.path())
347 if (w->isMinimized())
348 w->showNormal();
349 w->setActiveWindow();
350 w->raise();
351 break;
356 else
358 if (doc->URL().fileName() == i18n("Untitled") && m_editView->gridIsEmpty()){
359 // neither saved nor has content, as good as new
360 openDocumentFile(url);
362 else
364 KWordQuizApp *new_window= new KWordQuizApp();
365 new_window->show();
366 new_window->openDocumentFile(url);
372 void KWordQuizApp::openDocumentFile(const KURL& url)
374 slotStatusMsg(i18n("Opening file..."));
375 if (!url.isEmpty()) {
376 doc->openDocument( url);
377 m_dirWatch->addFile(url.path());
378 setCaption(doc->URL().fileName(), false);
379 fileOpenRecent->addURL( url );
380 updateMode(Prefs::mode());
382 slotStatusMsg(i18n("Ready"));
386 KWordQuizDoc *KWordQuizApp::getDocument() const
388 return doc;
391 void KWordQuizApp::saveOptions()
393 fileOpenRecent->saveEntries(kapp->config(), "Recent Files");
394 Prefs::writeConfig();
398 void KWordQuizApp::readOptions()
400 //Prefs::readConfig();
401 fileOpenRecent->loadEntries(kapp->config(), "Recent Files");
404 void KWordQuizApp::saveProperties(KConfig *_cfg)
406 if(doc->URL().fileName()!=i18n("Untitled") && !doc->isModified())
408 // saving to tempfile not necessary
411 else
413 KURL url=doc->URL();
414 _cfg->writeEntry("filename", url.url());
415 _cfg->writeEntry("modified", doc->isModified());
416 QString tempname = kapp->tempSaveName(url.url());
417 QString tempurl= KURL::encode_string(tempname);
418 KURL _url(tempurl);
419 doc->saveDocument(_url);
424 void KWordQuizApp::readProperties(KConfig* _cfg)
426 QString filename = _cfg->readEntry("filename", "");
427 KURL url(filename);
428 bool modified = _cfg->readBoolEntry("modified", false);
429 if(modified)
431 bool canRecover;
432 QString tempname = kapp->checkRecoverFile(filename, canRecover);
433 KURL _url(tempname);
435 if(canRecover)
437 doc->openDocument(_url);
438 doc->setModified();
439 setCaption(_url.fileName(),true);
440 QFile::remove(tempname);
443 else
445 if(!filename.isEmpty())
447 doc->openDocument(url);
448 setCaption(url.fileName(),false);
453 bool KWordQuizApp::queryClose()
455 bool f = doc->saveModified();
456 if (f)
457 if (m_dirWatch->contains(doc->URL().path()))
458 m_dirWatch->removeFile(doc->URL().path());
459 return f;
462 bool KWordQuizApp::queryExit()
464 saveOptions();
465 return true;
468 /////////////////////////////////////////////////////////////////////
469 // SLOT IMPLEMENTATION
470 /////////////////////////////////////////////////////////////////////
472 void KWordQuizApp::slotFileNew()
474 slotStatusMsg(i18n("Opening a new document window..."));
475 if (doc->URL().fileName() == i18n("Untitled") && m_editView->gridIsEmpty()){
476 // neither saved nor has content, as good as new
478 else
480 KWordQuizApp *new_window= new KWordQuizApp();
481 new_window->show();
483 slotStatusMsg(i18n("Ready"));
486 void KWordQuizApp::slotFileOpen()
488 slotStatusMsg(i18n("Opening file..."));
490 QCheckBox * cb = new QCheckBox(i18n("&Join selected files into one list"), 0, 0);
491 cb -> setChecked(false);
493 QString filter = i18n("*.kvtml *.wql *.xml.gz *.csv|All Supported Documents\n*.kvtml|KDE Vocabulary Document\n*.wql|KWordQuiz Document\n*.xml.gz|Pauker Lesson\n*.csv|Comma-Separated Values");
494 KFileDialog *fd = new KFileDialog(QString::null, filter, this, 0, true, cb);
495 fd -> setOperationMode(KFileDialog::Opening);
496 fd -> setMode(KFile::Files | KFile::ExistingOnly);
497 fd -> setCaption(i18n("Open Vocabulary Document"));
499 if (fd->exec() == QDialog::Accepted)
501 KURL::List l = fd -> selectedURLs();
502 bool append = ((cb -> isChecked()) && (l.count() > 1));
504 if (append)
506 KWordQuizApp * w;
507 if (doc->URL().fileName() == i18n("Untitled") && m_editView->gridIsEmpty()){
508 // neither saved nor has content, as good as new
509 w = this;
511 else
513 w = new KWordQuizApp();
514 w->show();
517 KURL::List::iterator it;
518 int i = 0;
519 for(it = l.begin(); it != l.end(); ++it)
521 w->getDocument()->openDocument(*it, true, i);
522 i++;
525 else
527 KURL::List::iterator it;
528 for(it = l.begin(); it != l.end(); ++it)
530 openURL(*it);
535 delete (fd); //deletes cb also
537 slotStatusMsg(i18n("Ready"));
540 void KWordQuizApp::slotFileOpenRecent(const KURL& url)
542 slotStatusMsg(i18n("Opening file..."));
543 fileOpenRecent->setCurrentItem(-1);
544 openURL(url);
545 slotStatusMsg(i18n("Ready"));
548 void KWordQuizApp::slotFileSave()
550 slotStatusMsg(i18n("Saving file..."));
551 if (doc->URL().fileName() == i18n("Untitled") )
553 slotFileSaveAs();
555 else
557 doc->saveDocument(doc->URL());
559 slotStatusMsg(i18n("Ready"));
562 void KWordQuizApp::slotFileSaveAs()
564 slotStatusMsg(i18n("Saving file with a new filename..."));
565 saveAsFileName();
566 slotStatusMsg(i18n("Ready"));
569 bool KWordQuizApp::saveAsFileName( )
572 bool success = false;
574 QString filter = i18n("*.kvtml|KDE Vocabulary Document\n*.wql|KWordQuiz Document\n*.csv|Comma-Separated Values\n*.html|Hypertext Markup Language");
575 KFileDialog *fd = new KFileDialog(QString::null, filter, this, 0, true);
576 fd -> setOperationMode(KFileDialog::Saving);
577 fd -> setCaption(i18n("Save Vocabulary Document As"));
579 if (fd->exec() == QDialog::Accepted)
581 KURL url = fd -> selectedURL();
582 if(!url.isEmpty()){
584 //@todo check that a valid extension was really given
585 if (!url.fileName().contains('.'))
587 if (fd->currentFilter() == "*.wql")
588 url = KURL(url.path() + ".wql");
589 else if (fd->currentFilter() == "*.csv")
590 url = KURL(url.path() + ".csv");
591 else if (fd->currentFilter() == "*.html")
592 url = KURL(url.path() + ".html");
593 else
594 url = KURL(url.path() + ".kvtml");
597 QFileInfo fileinfo(url.path());
598 if (fileinfo.exists() && KMessageBox::questionYesNo(0,
599 i18n("<qt>The file<br><b>%1</b><br>already exists. Do you want to overwrite it?</qt>")
600 .arg(url.path())) == KMessageBox::No)
602 // do nothing
604 else
606 if (m_dirWatch ->contains(doc->URL().path()))
607 m_dirWatch ->removeFile(doc->URL().path());
608 doc->saveDocument(url);
609 m_dirWatch->addFile(url.path());
610 fileOpenRecent->addURL(url);
611 setCaption(doc->URL().fileName(), doc->isModified());
612 success = true;
616 delete(fd);
617 return success;
620 void KWordQuizApp::slotFileClose()
622 slotStatusMsg(i18n("Closing file..."));
624 if (memberList->count() > 1)
625 close();
626 else
627 if (queryClose())
629 doc->newDocument();
630 setCaption(doc->URL().fileName(), doc->isModified());
631 delete (m_editView);
632 initView();
633 slotQuizEditor();
634 slotUndoChange(i18n("Cannot &Undo"), false);
635 updateMode(Prefs::mode());
636 m_editView ->setFocus();
639 slotStatusMsg(i18n("Ready"));
642 void KWordQuizApp::slotFilePrint()
644 slotStatusMsg(i18n("Printing..."));
645 WQPrintDialogPage * p = new WQPrintDialogPage(this);
646 KPrinter printer;
647 printer.addDialogPage(p);
648 printer.setFullPage(true);
649 if (printer.setup(this))
651 m_editView->print(&printer);
654 slotStatusMsg(i18n("Ready"));
657 void KWordQuizApp::slotFileQuit()
659 slotStatusMsg(i18n("Exiting..."));
660 saveOptions();
661 // close the first window, the list makes the next one the first again.
662 // This ensures that queryClose() is called on each window to ask for closing
663 KMainWindow* w;
664 if(memberList)
666 for(w=memberList->first(); w!=0; w=memberList->next())
668 // only close the window if the closeEvent is accepted. If the user presses Cancel on the saveModified() dialog,
669 // the window and the application stay open.
670 if(!w->close())
671 break;
676 void KWordQuizApp::slotUndoChange( const QString & text, bool enabled )
678 editUndo->setText(text);
679 editUndo->setEnabled(enabled);
682 void KWordQuizApp::slotEditUndo()
684 slotStatusMsg(i18n("Undoing previous command..."));
685 m_editView->doEditUndo();
686 slotStatusMsg(i18n("Ready"));
689 void KWordQuizApp::slotEditCut()
691 slotStatusMsg(i18n("Cutting selection..."));
692 m_editView->doEditCut();
693 slotStatusMsg(i18n("Ready"));
696 void KWordQuizApp::slotEditCopy()
698 slotStatusMsg(i18n("Copying selection to clipboard..."));
699 m_editView->doEditCopy();
700 slotStatusMsg(i18n("Ready"));
703 void KWordQuizApp::slotEditPaste()
705 slotStatusMsg(i18n("Inserting clipboard contents..."));
706 m_editView->doEditPaste();
707 slotStatusMsg(i18n("Ready"));
710 void KWordQuizApp::slotEditClear()
712 slotStatusMsg(i18n("Clearing the selected cells..."));
713 m_editView->doEditClear();
714 slotStatusMsg(i18n("Ready"));
717 void KWordQuizApp::slotEditInsert()
719 slotStatusMsg(i18n("Inserting rows..."));
720 m_editView->doEditInsert();
721 slotStatusMsg(i18n("Ready"));
724 void KWordQuizApp::slotEditDelete()
726 slotStatusMsg(i18n("Deleting selected rows..."));
727 m_editView->doEditDelete();
728 slotStatusMsg(i18n("Ready"));
731 void KWordQuizApp::slotEditMarkBlank()
733 slotStatusMsg(i18n("Marking selected text as a blank..."));
734 m_editView->doEditMarkBlank();
735 slotStatusMsg(i18n("Ready"));
738 void KWordQuizApp::slotEditUnmarkBlank()
740 slotStatusMsg(i18n("Removing blank markings..."));
741 m_editView->doEditUnmarkBlank();
742 slotStatusMsg(i18n("Ready"));
745 void KWordQuizApp::slotEditFind()
747 slotStatusMsg(i18n("Searching for indicated text..."));
748 KMessageBox::sorry(0, i18n("Not implemented yet"));
749 slotStatusMsg(i18n("Ready"));
752 void KWordQuizApp::slotVocabLanguages()
754 slotStatusMsg(i18n("Setting the column titles of the vocabulary..."));
755 DlgLanguage* dlg;
756 dlg = new DlgLanguage(this, "dlg_lang", true);
757 dlg->setLanguage(1, m_editView -> horizontalHeader()->label(0));
758 dlg->setLanguage(2, m_editView -> horizontalHeader()->label(1));
759 dlg->disableResize();
760 if (dlg->exec() == KDialogBase::Accepted)
762 m_editView -> horizontalHeader()->setLabel(0, dlg->Language(1));
763 m_editView -> horizontalHeader()->setLabel(1, dlg->Language(2));
764 updateMode(Prefs::mode());
766 slotStatusMsg(i18n("Ready"));
769 void KWordQuizApp::slotVocabFont()
771 slotStatusMsg(i18n("Setting the font of the vocabulary..."));
772 KFontDialog* dlg;
773 dlg = new KFontDialog(this, "dlg_font", false, true);
774 dlg->setFont(m_editView -> font());
775 if (dlg->exec() == KFontDialog::Accepted)
777 m_editView ->setFont(dlg->font());
778 Prefs::setEditorFont(dlg->font());
779 doc->setModified(true);
781 slotStatusMsg(i18n("Ready"));
784 void KWordQuizApp::slotVocabKeyboard()
786 slotStatusMsg(i18n("Changing the keyboard layout..."));
787 KMessageBox::sorry(0, i18n("Not implemented yet"));
788 slotStatusMsg(i18n("Ready"));
791 void KWordQuizApp::slotVocabChar()
793 slotStatusMsg(i18n("Inserting special character..."));
794 m_editView->doVocabSpecChar();
795 slotStatusMsg(i18n("Ready"));
798 void KWordQuizApp::slotVocabRC()
800 slotStatusMsg(i18n("Changing row and column properties..."));
801 m_editView->doVocabRC();
802 slotStatusMsg(i18n("Ready"));
805 void KWordQuizApp::slotVocabSort()
807 slotStatusMsg(i18n("Sorting the vocabulary..."));
808 m_editView->doVocabSort();
809 slotStatusMsg(i18n("Ready"));
812 void KWordQuizApp::slotVocabShuffle()
814 slotStatusMsg(i18n("Randomizing the vocabulary..."));
815 m_editView->doVocabShuffle();
816 slotStatusMsg(i18n("Ready"));
819 void KWordQuizApp::slotMode0()
821 slotStatusMsg(i18n("Updating mode..."));
822 if (Prefs::mode() < 5) {
823 updateMode(Prefs::mode() + 1);
825 else
827 updateMode(1);
829 slotStatusMsg(i18n("Ready"));
832 void KWordQuizApp::slotMode1()
834 slotStatusMsg(i18n("Updating mode..."));
835 updateMode(1);
836 slotStatusMsg(i18n("Ready"));
839 void KWordQuizApp::slotMode2()
841 slotStatusMsg(i18n("Updating mode..."));
842 updateMode(2);
843 slotStatusMsg(i18n("Ready"));
846 void KWordQuizApp::slotMode3()
848 slotStatusMsg(i18n("Updating mode..."));
849 updateMode(3);
850 slotStatusMsg(i18n("Ready"));
853 void KWordQuizApp::slotMode4()
855 slotStatusMsg(i18n("Updating mode..."));
856 updateMode(4);
857 slotStatusMsg(i18n("Ready"));
860 void KWordQuizApp::slotMode5()
862 slotStatusMsg(i18n("Updating mode..."));
863 updateMode(5);
864 slotStatusMsg(i18n("Ready"));
867 void KWordQuizApp::slotQuizEditor()
869 slotStatusMsg(i18n("Starting editor session..."));
870 updateSession(WQQuiz::qtEditor);
871 slotStatusMsg(i18n("Ready"));
874 void KWordQuizApp::slotQuizFlash()
876 slotStatusMsg(i18n("Starting flashcard session..."));
877 updateSession(WQQuiz::qtFlash);
878 slotStatusMsg(i18n("Ready"));
881 void KWordQuizApp::slotQuizMultiple()
883 slotStatusMsg(i18n("Starting multiple choice session..."));
884 updateSession(WQQuiz::qtMultiple);
885 slotStatusMsg(i18n("Ready"));
888 void KWordQuizApp::slotQuizQA()
890 slotStatusMsg(i18n("Starting question & answer session..."));
891 updateSession(WQQuiz::qtQA);
892 slotStatusMsg(i18n("Ready"));
895 void KWordQuizApp::updateSession(WQQuiz::QuizType qt)
897 if (m_quiz != 0)
899 delete(m_quiz);
900 m_quiz = 0;
903 switch( m_quizType ){
904 case WQQuiz::qtEditor:
906 break;
907 case WQQuiz::qtFlash:
908 if (m_flashView != 0)
910 delete(m_flashView);
911 m_flashView = 0;
913 break;
914 case WQQuiz::qtMultiple:
915 if (m_multipleView != 0)
917 delete(m_multipleView);
918 m_multipleView = 0;
920 break;
921 case WQQuiz::qtQA:
922 if (m_qaView != 0)
924 delete(m_qaView);
925 m_qaView = 0;
927 break;
930 m_quizType = qt;
931 updateActions(qt);
933 switch( m_quizType ){
934 case WQQuiz::qtEditor:
935 m_editView->show();
936 setCentralWidget(m_editView);
937 m_editView -> setFocus();
938 break;
939 case WQQuiz::qtFlash:
940 m_quiz = new WQQuiz(m_editView);
941 connect(m_quiz, SIGNAL(checkingAnswer(int )), m_editView, SLOT(slotCheckedAnswer(int )));
942 m_quiz ->setQuizType(WQQuiz::qtFlash);
943 m_quiz->setQuizMode(Prefs::mode());
944 if (m_quiz -> init())
946 m_editView->saveCurrentSelection(true);
947 m_editView->hide();
948 m_flashView = new FlashView(this);
949 connect(quizCheck, SIGNAL(activated()), m_flashView, SLOT(slotFlip()));
950 connect(flashKnow, SIGNAL(activated()), m_flashView, SLOT(slotKnow()));
951 connect(flashDontKnow, SIGNAL(activated()), m_flashView, SLOT(slotDontKnow()));
952 connect(quizRestart, SIGNAL(activated()), m_flashView, SLOT(slotRestart()));
953 connect(quizRepeatErrors, SIGNAL(activated()), m_flashView, SLOT(slotRepeat()));
954 connect(this, SIGNAL(settingsChanged()), m_flashView, SLOT(slotApplySettings()));
956 setCentralWidget(m_flashView);
957 m_flashView -> setQuiz(m_quiz);
958 m_flashView ->init();
959 m_flashView->show();
961 else
963 delete(m_quiz);
964 m_quiz = 0;
966 break;
967 case WQQuiz::qtMultiple:
968 m_quiz = new WQQuiz(m_editView);
969 connect(m_quiz, SIGNAL(checkingAnswer(int )), m_editView, SLOT(slotCheckedAnswer(int )));
970 m_quiz ->setQuizType(WQQuiz::qtMultiple);
971 m_quiz->setQuizMode(Prefs::mode());
972 if (m_quiz -> init())
974 m_editView->saveCurrentSelection(true);
975 m_editView->hide();
976 m_multipleView = new MultipleView(this);
977 connect(quizCheck, SIGNAL(activated()), m_multipleView, SLOT(slotCheck()));
978 connect(quizRestart, SIGNAL(activated()), m_multipleView, SLOT(slotRestart()));
979 connect(quizRepeatErrors, SIGNAL(activated()), m_multipleView, SLOT(slotRepeat()));
980 connect(this, SIGNAL(settingsChanged()), m_multipleView, SLOT(slotApplySettings()));
982 setCentralWidget(m_multipleView);
984 m_multipleView -> setQuiz(m_quiz);
985 m_multipleView ->init();
986 m_multipleView->show();
988 else
990 delete(m_quiz);
991 m_quiz = 0;
993 break;
994 case WQQuiz::qtQA:
995 m_quiz = new WQQuiz(m_editView);
996 connect(m_quiz, SIGNAL(checkingAnswer(int )), m_editView, SLOT(slotCheckedAnswer(int )));
997 m_quiz ->setQuizType(WQQuiz::qtQA);
998 m_quiz->setQuizMode(Prefs::mode());
999 if (m_quiz -> init())
1001 m_editView->saveCurrentSelection(true);
1002 m_editView->hide();
1003 m_qaView = new QAView(this);
1004 connect(quizCheck, SIGNAL(activated()), m_qaView, SLOT(slotCheck()));
1005 connect(qaHint, SIGNAL(activated()), m_qaView, SLOT(slotHint()));
1006 connect(quizRestart, SIGNAL(activated()), m_qaView, SLOT(slotRestart()));
1007 connect(quizRepeatErrors, SIGNAL(activated()), m_qaView, SLOT(slotRepeat()));
1008 connect(this, SIGNAL(settingsChanged()), m_qaView, SLOT(slotApplySettings()));
1010 setCentralWidget(m_qaView);
1012 m_qaView -> setQuiz(m_quiz);
1013 m_qaView ->init();
1014 m_qaView->show();
1016 else
1018 delete(m_quiz);
1019 m_quiz = 0;
1021 break;
1026 /** Configure notifications */
1027 void KWordQuizApp::slotConfigureNotifications( )
1029 KNotifyDialog::configure(this, "Notification Configuration Dialog");
1032 /** Configure kwordquiz */
1033 void KWordQuizApp::slotConfigure()
1035 if ( KWordQuizPrefs::showDialog( "settings" ) )
1036 return;
1038 //KConfigDialog didn't find an instance of this dialog, so lets create it :
1039 KWordQuizPrefs* dialog = new KWordQuizPrefs( this, "settings", Prefs::self() );
1040 connect(dialog, SIGNAL(settingsChanged()), this, SLOT(slotApplyPreferences()));
1041 dialog->show();
1044 void KWordQuizApp::slotApplyPreferences()
1046 kdDebug() << "Prefs Update" << endl;
1047 editMarkBlank->setEnabled(Prefs::enableBlanks());
1048 editUnmarkBlank->setEnabled(Prefs::enableBlanks());
1049 m_editView->viewport()->repaint(true);
1050 updateSpecialCharIcons();
1051 emit settingsChanged();
1054 void KWordQuizApp::updateSpecialCharIcons( )
1056 for (int i = 0; i < 9; i++){
1057 KAction * act = actionCollection()->action(QString("char_" + QString::number(i + 1)).latin1());
1058 act->setIcon(charIcon(Prefs::specialCharacters()[i]));
1059 act->setToolTip(i18n("Inserts the character %1").arg(Prefs::specialCharacters()[i]));
1063 QString KWordQuizApp::charIcon(const QChar & c)
1065 ///Create a name and path for the icon
1066 QString s = locateLocal("icon", "char" + QString::number(c.unicode()) + ".png");
1068 ///No need to redraw if it already exists
1069 if (KStandardDirs::exists(s))
1070 return s;
1072 QRect r(4, 4, 120, 120);
1074 ///A font to draw the character with
1075 QFont font("sans");
1076 font.setPixelSize(100);
1077 font.setWeight(QFont::Bold);
1079 ///Create the pixmap
1080 QPixmap pm(128, 128);
1081 pm.fill(Qt::white);
1082 QPainter p(&pm);
1083 p.setFont(font);
1084 p.setPen(Qt::blue);
1085 p.drawText(r, Qt::AlignCenter, (QString) c);
1087 ///Create transparency mask
1088 QBitmap bm(128, 128);
1089 bm.fill(Qt::color0);
1090 QPainter b(&bm);
1091 b.setFont(font);
1092 b.setPen(Qt::color1);
1093 b.drawText(r, Qt::AlignCenter, (QString) c);
1095 ///Mask the pixmap
1096 pm.setMask(bm);
1098 ///Save the icon to disk
1099 pm.save(s, "PNG");
1101 return s;
1104 void KWordQuizApp::slotStatusMsg(const QString &text)
1106 statusBar()->clear();
1107 statusBar()->message(text);
1111 \fn KWordQuizApp::updateMode(int m)
1113 void KWordQuizApp::updateMode(int m)
1115 if (m_quiz != 0)
1116 if (KMessageBox::warningContinueCancel(this, i18n("This will restart your quiz. Do you wish to continue?"), QString::null, KStdGuiItem::cont(), "askModeQuiz") != KMessageBox::Continue)
1118 mode1->setChecked(Prefs::mode() == 1);
1119 mode2->setChecked(Prefs::mode() == 2);
1120 mode3->setChecked(Prefs::mode() == 3);
1121 mode4->setChecked(Prefs::mode() == 4);
1122 mode5->setChecked(Prefs::mode() == 5);
1123 return;
1126 Prefs::setMode(m);
1127 QString s1 = m_editView -> horizontalHeader()->label(0);
1128 QString s2 = m_editView -> horizontalHeader()->label(1);
1130 mode1->setText(i18n("&1 %1 -> %2 In Order").arg(s1).arg(s2));
1131 mode2->setText(i18n("&2 %1 -> %2 In Order").arg(s2).arg(s1));
1132 mode3->setText(i18n("&3 %1 -> %2 Randomly").arg(s1).arg(s2));
1133 mode4->setText(i18n("&4 %1 -> %2 Randomly").arg(s2).arg(s1));
1134 mode5->setText(i18n("&5 %1 <-> %2 Randomly").arg(s1).arg(s2));
1136 mode1->setChecked(Prefs::mode() == 1);
1137 mode2->setChecked(Prefs::mode() == 2);
1138 mode3->setChecked(Prefs::mode() == 3);
1139 mode4->setChecked(Prefs::mode() == 4);
1140 mode5->setChecked(Prefs::mode() == 5);
1142 KPopupMenu *popup = mode->popupMenu();
1143 popup->setItemChecked(0, Prefs::mode() == 1);
1144 popup->setItemChecked(1, Prefs::mode() == 2);
1145 popup->setItemChecked(2, Prefs::mode() == 3);
1146 popup->setItemChecked(3, Prefs::mode() == 4);
1147 popup->setItemChecked(4, Prefs::mode() == 5);
1149 popup->changeItem(0, i18n("&1 %1 -> %2 In Order").arg(s1).arg(s2));
1150 popup->changeItem(1, i18n("&2 %1 -> %2 In Order").arg(s2).arg(s1));
1151 popup->changeItem(2, i18n("&3 %1 -> %2 Randomly").arg(s1).arg(s2));
1152 popup->changeItem(3, i18n("&4 %1 -> %2 Randomly").arg(s2).arg(s1));
1153 popup->changeItem(4, i18n("&5 %1 <-> %2 Randomly").arg(s1).arg(s2));
1155 QString s;
1156 mode->setIcon("mode" + s.setNum(Prefs::mode()));
1158 switch( Prefs::mode() ){
1159 case 1:
1160 statusBar()->changeItem(i18n("%1 -> %2 In Order").arg(s1).arg(s2), ID_STATUS_MSG_MODE);
1161 break;
1162 case 2:
1163 statusBar()->changeItem(i18n("%1 -> %2 In Order").arg(s2).arg(s1), ID_STATUS_MSG_MODE);
1164 break;
1165 case 3:
1166 statusBar()->changeItem(i18n("%1 -> %2 Randomly").arg(s1).arg(s2), ID_STATUS_MSG_MODE);
1167 break;
1168 case 4:
1169 statusBar()->changeItem(i18n("%1 -> %2 Randomly").arg(s2).arg(s1), ID_STATUS_MSG_MODE);
1170 break;
1171 case 5:
1172 statusBar()->changeItem(i18n("%1 <-> %2 Randomly").arg(s1).arg(s2), ID_STATUS_MSG_MODE);
1173 break;
1176 if (m_quiz !=0)
1177 updateSession(m_quizType);
1180 void KWordQuizApp::slotInsertChar( int i )
1182 if (m_qaView != 0)
1183 m_qaView->slotSpecChar(Prefs::specialCharacters()[i - 1]);
1184 else
1185 if (centralWidget() == m_editView)
1186 m_editView->slotSpecChar(Prefs::specialCharacters()[i - 1]);
1189 void KWordQuizApp::slotActionHighlighted( KAction * action, bool hl)
1191 if (!hl)
1192 slotStatusMsg(i18n("Ready"));
1195 void KWordQuizApp::slotContextMenuRequested(int row, int col, const QPoint & pos)
1197 QWidget *w = factory()->container("editor_popup", this);
1198 QPopupMenu *popup = static_cast<QPopupMenu *>(w);
1199 popup->exec(pos);
1202 void KWordQuizApp::updateActions( WQQuiz::QuizType qt )
1204 bool fEdit = (qt == WQQuiz::qtEditor);
1206 fileSave->setEnabled(fEdit);
1207 fileSaveAs->setEnabled(fEdit);
1208 filePrint->setEnabled(fEdit);
1209 //editFind->setEnabled(fEdit);
1210 editClear->setEnabled(fEdit);
1211 editInsert->setEnabled(fEdit);
1212 editDelete->setEnabled(fEdit);
1213 editMarkBlank->setEnabled(fEdit && Prefs::enableBlanks());
1214 editUnmarkBlank->setEnabled(fEdit && Prefs::enableBlanks());
1215 vocabLanguages->setEnabled(fEdit);
1216 vocabFont->setEnabled(fEdit);
1217 //vocabKeyboard->setEnabled(fEdit);
1218 vocabRC->setEnabled(fEdit);
1219 vocabSort->setEnabled(fEdit);
1220 vocabShuffle->setEnabled(fEdit);
1222 quizEditor->setEnabled(qt != WQQuiz::qtEditor);
1223 quizFlash->setEnabled(qt != WQQuiz::qtFlash);
1224 quizMultiple->setEnabled(qt != WQQuiz::qtMultiple);
1225 quizQA->setEnabled(qt != WQQuiz::qtQA);
1227 quizCheck->setEnabled(qt != WQQuiz::qtEditor);
1228 quizRestart->setEnabled(qt != WQQuiz::qtEditor);
1229 quizRepeatErrors->setEnabled(false);
1231 flashKnow->setEnabled(qt == WQQuiz::qtFlash);
1232 flashDontKnow->setEnabled(qt == WQQuiz::qtFlash);
1234 qaHint->setEnabled(qt == WQQuiz::qtQA);
1236 toolBar("quizToolBar")->setHidden(qt == WQQuiz::qtEditor);
1240 #include "kwordquiz.moc"