Warning, file /education/parley/src/parleydocument.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002     SPDX-FileCopyrightText: 2007-2008 Frederik Gladhorn <frederik.gladhorn@kdemail.net>
0003     SPDX-License-Identifier: GPL-2.0-or-later
0004 */
0005 
0006 #include "parleydocument.h"
0007 
0008 #include "editor/editor.h"
0009 #include "parleymainwindow.h"
0010 #include "prefs.h"
0011 
0012 #include "dashboard/dashboard.h"
0013 #include "settings/documentproperties.h"
0014 #include "vocabularyview.h"
0015 
0016 #include <KEduVocExpression>
0017 #include <KEduVocLeitnerBox>
0018 #include <KEduVocLesson>
0019 #include <KEduVocWordtype>
0020 
0021 #include <KRecentFilesAction>
0022 #include <QFileDialog>
0023 #include <QMimeDatabase>
0024 #include <QStandardPaths>
0025 #include <knewstuff_version.h>
0026 #include <KEMailSettings>
0027 #include <KMessageBox>
0028 #include <KProcess>
0029 #include <QTemporaryDir>
0030 
0031 #include <QDialog>
0032 #include <QDialogButtonBox>
0033 #include <QTimer>
0034 
0035 #ifdef HAVE_LIBXSLT
0036 #include "exportdialog.h"
0037 #include <libxml/parser.h>
0038 #include <libxml/tree.h>
0039 #include <libxslt/transform.h>
0040 #include <libxslt/xslt.h>
0041 #include <libxslt/xsltInternals.h>
0042 #include <libxslt/xsltutils.h>
0043 #endif
0044 
0045 #include "settings/languageproperties.h"
0046 
0047 namespace DocumentHelper
0048 {
0049 void fetchGrammar(KEduVocDocument *doc, int languageIndex)
0050 {
0051     QString locale = doc->identifier(languageIndex).locale();
0052 
0053     QUrl location(QUrl::fromUserInput(QStringLiteral("https://edu.kde.org/parley/locale/") + locale.split('_').at(0).toLower() + QStringLiteral(".kvtml")));
0054 
0055     KEduVocDocument grammarDoc;
0056     if (grammarDoc.open(location) == KEduVocDocument::NoError) {
0057         doc->identifier(languageIndex).setArticle(grammarDoc.identifier(0).article());
0058         doc->identifier(languageIndex).setPersonalPronouns(grammarDoc.identifier(0).personalPronouns());
0059         // @todo        m_doc->identifier(index).setDeclension(grammarDoc.identifier(0).declension());
0060         doc->identifier(languageIndex).setTenseList(grammarDoc.identifier(0).tenseList());
0061     } else {
0062         qDebug() << "Download of " << location << " failed.";
0063     }
0064 }
0065 } // namespace DocumentHelper
0066 
0067 ParleyDocument::ParleyDocument(ParleyMainWindow *parleyMainWindow)
0068     : QObject(parleyMainWindow)
0069     , m_parleyApp(parleyMainWindow)
0070     , m_doc(new KEduVocDocument)
0071 {
0072 }
0073 
0074 ParleyDocument::~ParleyDocument()
0075 {
0076     close();
0077 }
0078 
0079 std::shared_ptr<KEduVocDocument> ParleyDocument::document()
0080 {
0081     // If there is no present vocabulary document, create an empty one.
0082     if (!m_doc) {
0083         m_doc.reset(new KEduVocDocument);
0084     }
0085 
0086     return m_doc;
0087 }
0088 
0089 void ParleyDocument::setTitle(const QString &title)
0090 {
0091     m_doc->setTitle(title);
0092 }
0093 
0094 void ParleyDocument::slotFileNew()
0095 {
0096     if (queryClose()) {
0097         newDocument(true);
0098     }
0099 }
0100 
0101 void ParleyDocument::newDocument(bool wizard)
0102 {
0103     std::shared_ptr<KEduVocDocument> newDoc(new KEduVocDocument);
0104 
0105     initializeDefaultGrammar(newDoc.get());
0106     setDefaultDocumentProperties(newDoc.get());
0107     bool showGrammarDialog = false;
0108     bool fetchGrammarOnline = false;
0109     if (wizard) {
0110         DocumentProperties *titleAuthorWidget = new DocumentProperties(newDoc.get(), true, m_parleyApp);
0111 
0112         QDialogButtonBox *button_dialog = new QDialogButtonBox;
0113         button_dialog->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
0114 
0115         QVBoxLayout *layout = new QVBoxLayout;
0116         layout->addWidget(titleAuthorWidget);
0117         layout->addWidget(button_dialog);
0118 
0119         QDialog *titleAuthorDialog = new QDialog;
0120         titleAuthorDialog->setLayout(layout);
0121         titleAuthorDialog->setWindowTitle(i18nc("@title:window document properties", "Properties for %1", newDoc->url().url()));
0122 
0123         connect(titleAuthorDialog, &QDialog::accepted, titleAuthorWidget, &DocumentProperties::accept);
0124         connect(button_dialog, &QDialogButtonBox::accepted, titleAuthorDialog, &QDialog::accept);
0125         connect(button_dialog, &QDialogButtonBox::rejected, titleAuthorDialog, &QDialog::reject);
0126 
0127         if (titleAuthorDialog->exec()) {
0128             showGrammarDialog = titleAuthorWidget->grammarCheckBox->isChecked();
0129             fetchGrammarOnline = titleAuthorWidget->downloadGrammarCheckBox->isChecked();
0130             delete titleAuthorDialog;
0131         } else {
0132             delete titleAuthorDialog;
0133             return;
0134         }
0135     }
0136 
0137     close();
0138     m_doc = std::move(newDoc);
0139     Q_EMIT documentChanged(m_doc);
0140     enableAutoBackup(Prefs::autoBackup());
0141 
0142     if (fetchGrammarOnline) {
0143         DocumentHelper::fetchGrammar(m_doc.get(), 0);
0144         DocumentHelper::fetchGrammar(m_doc.get(), 1);
0145     }
0146     if (showGrammarDialog) {
0147         languageProperties();
0148     }
0149 
0150     m_parleyApp->showEditor();
0151 }
0152 
0153 void ParleyDocument::slotFileOpen()
0154 {
0155     if (queryClose()) {
0156         ///@todo frameworks check filters are fixed in kvocdoc
0157         ///@todo frameworks check how to add child checkbox to this dialog
0158         QFileDialog dialog(m_parleyApp, i18nc("@title:window", "Open Vocabulary Collection"), QString(), KEduVocDocument::pattern(KEduVocDocument::Reading));
0159         QCheckBox *practiceCheckBox = new QCheckBox(i18n("Open in practice &mode"), &dialog);
0160         practiceCheckBox->setChecked(m_parleyApp->currentComponent() != ParleyMainWindow::EditorComponent);
0161         dialog.setFileMode(QFileDialog::ExistingFile);
0162         if (dialog.exec() && !dialog.selectedFiles().isEmpty() && open(QUrl::fromLocalFile(dialog.selectedFiles().constFirst()))) {
0163             if (practiceCheckBox->isChecked()) {
0164                 m_parleyApp->showPracticeConfiguration();
0165             } else {
0166                 m_parleyApp->showEditor();
0167             }
0168         }
0169     }
0170 }
0171 
0172 void ParleyDocument::slotFileOpenRecent(const QUrl &url)
0173 {
0174     if (queryClose() && open(url)) {
0175         m_parleyApp->showEditor(); ///@todo: start practice directly depending on current component
0176     }
0177 }
0178 
0179 bool ParleyDocument::open(const QUrl &url)
0180 {
0181     if (url.path().isEmpty()) {
0182         return false;
0183     }
0184 
0185     close();
0186 
0187     m_doc.reset(new KEduVocDocument);
0188     Q_EMIT documentChanged(m_doc);
0189     m_doc->setCsvDelimiter(Prefs::separator());
0190 
0191     bool isSuccess = false, isError = false;
0192 
0193     KEduVocDocument::ErrorCode ret = m_doc->open(url, KEduVocDocument::FileDefaultHandling);
0194     switch (ret) {
0195     case KEduVocDocument::NoError:
0196         isSuccess = true;
0197         break;
0198     case KEduVocDocument::FileLocked: {
0199         int exit = KMessageBox::warningYesNo(m_parleyApp,
0200                                              i18n("The vocabulary collection is locked by another process.  You can open the file if you take over the lock, "
0201                                                   "but you will lose any changes from the other process.\n\nDo you want to take over the lock?\n"),
0202                                              i18n("Take Over Lock"));
0203         if (exit == KMessageBox::Yes) { // attempt to steal lock
0204 
0205             ret = m_doc->open(url, KEduVocDocument::FileIgnoreLock);
0206             if (ret == KEduVocDocument::NoError) {
0207                 qDebug() << "Lock stolen";
0208                 isSuccess = true;
0209             } else {
0210                 isError = true;
0211             }
0212         } else { // Don't Steal continue work without saving !!!
0213         }
0214 
0215         break;
0216     }
0217     default:
0218         isError = true;
0219     }
0220 
0221     if (isSuccess) {
0222         qDebug() << "Open success.";
0223         // m_parleyApp->editor()->updateDocument();
0224         m_parleyApp->addRecentFile(url, m_doc->title());
0225 
0226         enableAutoBackup(Prefs::autoBackup());
0227 
0228     } else {
0229         if (isError) {
0230             KMessageBox::error(m_parleyApp,
0231                                i18n("Opening collection \"%1\" resulted in an error: %2", m_doc->url().url(), m_doc->errorDescription(ret)),
0232                                i18nc("@title:window", "Open Collection"));
0233         }
0234         m_doc.reset();
0235         Q_EMIT documentChanged(m_doc);
0236     }
0237 
0238     return isSuccess;
0239 }
0240 
0241 void ParleyDocument::close()
0242 {
0243     enableAutoBackup(false);
0244     if (m_doc) {
0245         m_doc.reset();
0246         Q_EMIT documentChanged(m_doc);
0247     }
0248 }
0249 
0250 bool ParleyDocument::queryClose()
0251 {
0252     if (!m_doc || !m_doc->isModified()) {
0253         return true;
0254     }
0255 
0256     bool canSave = Prefs::autoSave(); // save without asking
0257 
0258     if (!canSave) {
0259         int exit = KMessageBox::warningYesNoCancel(m_parleyApp,
0260                                                    i18n("Vocabulary is modified.\n\nSave file before exit?\n"),
0261                                                    QLatin1String(""),
0262                                                    KStandardGuiItem::save(),
0263                                                    KStandardGuiItem::discard());
0264         switch (exit) {
0265         case KMessageBox::Yes:
0266             canSave = true; // save and exit
0267             break;
0268         case KMessageBox::No:
0269             canSave = false; // don't save but exit
0270             break;
0271         case KMessageBox::Continue:
0272         default:
0273             return false; // continue work without saving !!!
0274         }
0275     }
0276 
0277     if (canSave) {
0278         save(); // save and exit
0279     }
0280 
0281     close();
0282     return true;
0283 }
0284 
0285 void ParleyDocument::openGHNS()
0286 {
0287     if (m_parleyApp->queryClose()) {
0288         QDir downloadDir(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + '/' + "kvtml/");
0289 
0290         downloadDir.mkpath(downloadDir.absolutePath());
0291 
0292         QUrl url = QUrl::fromUserInput(QFileDialog::getOpenFileName(m_parleyApp,
0293                                                                     i18nc("@title:window", "Open Downloaded Vocabulary Collection"),
0294                                                                     downloadDir.path(),
0295                                                                     KEduVocDocument::pattern(KEduVocDocument::Reading)));
0296 
0297         if (open(url)) {
0298             m_parleyApp->showPracticeConfiguration();
0299         }
0300     }
0301 }
0302 
0303 void ParleyDocument::save()
0304 {
0305     if (m_doc->url().fileName().isEmpty()) {
0306         saveAs();
0307         return;
0308     }
0309 
0310     // remove previous backup
0311     QFile::remove(m_doc->url().toLocalFile() + '~');
0312     QFile::copy(QFile::encodeName(m_doc->url().toLocalFile()), QFile::encodeName(m_doc->url().toLocalFile() + '~'));
0313 
0314     m_doc->setCsvDelimiter(Prefs::separator());
0315 
0316     Q_EMIT statesNeedSaving();
0317 
0318     QString newgenerator = QLatin1String("Parley ") + PARLEY_VERSION_STRING;
0319     m_doc->setGenerator(newgenerator);
0320 
0321     bool isSuccess = false, isError = false;
0322 
0323     KEduVocDocument::ErrorCode ret = m_doc->saveAs(m_doc->url(), KEduVocDocument::Automatic, KEduVocDocument::FileIgnoreLock);
0324 
0325     switch (ret) {
0326     case KEduVocDocument::NoError:
0327         isSuccess = true;
0328         break;
0329     case KEduVocDocument::FileLocked: {
0330         int exit = KMessageBox::warningYesNo(m_parleyApp,
0331                                              i18n("File \"%1\" is locked by another process.  You can save to the file if you take over the lock, but you will "
0332                                                   "lose any changes from the other process.\n\nDo you want to take over the lock?\n",
0333                                                   m_doc->url().url()),
0334                                              QLatin1String(""));
0335         if (exit == KMessageBox::Yes) {
0336             m_doc->setGenerator(newgenerator);
0337             ret = m_doc->saveAs(m_doc->url(), KEduVocDocument::Automatic, KEduVocDocument::FileIgnoreLock);
0338 
0339             if (ret == KEduVocDocument::NoError) {
0340                 isSuccess = true;
0341                 qDebug() << "Lock stolen";
0342             } else {
0343                 isError = true;
0344             }
0345         } else {
0346             // Intentionally empty else. Try to saveAs another filename
0347         }
0348         break;
0349     }
0350     default:
0351         isError = true;
0352     }
0353 
0354     if (isSuccess) {
0355         m_parleyApp->addRecentFile(m_doc->url(), m_doc->title());
0356         enableAutoBackup(Prefs::autoBackup());
0357     } else {
0358         if (isError) {
0359             KMessageBox::error(m_parleyApp,
0360                                i18n("Writing file \"%1\" resulted in an error: %2", m_doc->url().url(), m_doc->errorDescription(ret)),
0361                                i18nc("@title:window", "Save File"));
0362         }
0363         qDebug() << "Save failed trying save as for " << m_doc->url().url();
0364         saveAs();
0365     }
0366 }
0367 
0368 void ParleyDocument::saveAs(QUrl url)
0369 {
0370     if (!m_doc) {
0371         return;
0372     }
0373 
0374     if (url.isEmpty()) {
0375         url = QUrl::fromLocalFile(QFileDialog::getSaveFileName(m_parleyApp->parentWidget(),
0376                                                                i18nc("@title:window", "Save Vocabulary As"),
0377                                                                QString(),
0378                                                                KEduVocDocument::pattern(KEduVocDocument::Writing)));
0379 
0380         if (url.isEmpty()) {
0381             return;
0382         }
0383     }
0384 
0385     QFileInfo fileinfo(url.toLocalFile());
0386     if (fileinfo.exists()) {
0387         if (KMessageBox::warningContinueCancel(0,
0388                                                i18n("<qt>The file<p><b>%1</b></p>already exists. Do you want to overwrite it?</qt>", url.toLocalFile()),
0389                                                QString(),
0390                                                KStandardGuiItem::overwrite())
0391             == KMessageBox::Cancel) {
0392             return;
0393         }
0394     }
0395 
0396     QString msg = i18nc("@info:status saving a file", "Saving %1", url.toLocalFile());
0397 
0398     QFile::remove(url.toLocalFile() + '~'); // remove previous backup
0399     QFile::copy(QFile::encodeName(url.toLocalFile()), QFile::encodeName(QString(url.toLocalFile() + '~')));
0400 
0401     m_doc->setCsvDelimiter(Prefs::separator());
0402 
0403     if (!url.toLocalFile().contains('.')) {
0404         url.fromLocalFile(url.toLocalFile() + QLatin1String(".kvtml"));
0405     }
0406 
0407     bool isSuccess = false, isError = false;
0408     m_doc->setGenerator(QStringLiteral("Parley"));
0409     int ret = m_doc->saveAs(url, KEduVocDocument::Automatic);
0410     switch (ret) {
0411     case KEduVocDocument::NoError:
0412         isSuccess = true;
0413         break;
0414     case KEduVocDocument::FileLocked: {
0415         int exit = KMessageBox::warningYesNo(m_parleyApp,
0416                                              i18n("File \"%1\" is locked by another process.  You can save to the file if you take over the lock, but you will "
0417                                                   "lose any changes from the other process.\n\nDo you want to take over the lock?\n",
0418                                                   m_doc->url().url()),
0419                                              QLatin1String(""));
0420         if (exit == KMessageBox::Yes) { // attempt lock steal
0421             m_doc->setGenerator(QLatin1String("Parley ") + PARLEY_VERSION_STRING);
0422             ret = m_doc->saveAs(m_doc->url(), KEduVocDocument::Automatic, KEduVocDocument::FileIgnoreLock);
0423 
0424             if (ret == KEduVocDocument::NoError) {
0425                 isSuccess = true;
0426                 qDebug() << "Lock stolen";
0427             } else {
0428                 isError = true;
0429             }
0430             break;
0431         } else { // don't steal the lock
0432         }
0433 
0434         break;
0435     }
0436     default:
0437         isError = true;
0438         break;
0439     }
0440 
0441     if (isSuccess) {
0442         qDebug() << "SaveAs success.";
0443         m_parleyApp->addRecentFile(m_doc->url(), m_doc->title());
0444         Q_EMIT statesNeedSaving();
0445 
0446     } else {
0447         qDebug() << "SaveAs failed for " << m_doc->url().url() << " \nwhy " << m_doc->errorDescription(ret);
0448         if (isError) {
0449             KMessageBox::error(m_parleyApp,
0450                                i18n("Writing file \"%1\" resulted in an error: %2", m_doc->url().url(), m_doc->errorDescription(ret)),
0451                                i18nc("@title:window", "Save File"));
0452         }
0453     }
0454 }
0455 
0456 void ParleyDocument::initializeDefaultGrammar(KEduVocDocument *doc)
0457 {
0458     KEduVocWordType *root = doc->wordTypeContainer();
0459     KEduVocWordType *noun = new KEduVocWordType(i18n("Noun"), root);
0460     noun->setWordType(KEduVocWordFlag::Noun);
0461     root->appendChildContainer(noun);
0462 
0463     KEduVocWordType *nounChild = new KEduVocWordType(i18n("Masculine"), noun);
0464     nounChild->setWordType(KEduVocWordFlag::Noun | KEduVocWordFlag::Masculine);
0465     noun->appendChildContainer(nounChild);
0466     nounChild = new KEduVocWordType(i18n("Feminine"), noun);
0467     nounChild->setWordType(KEduVocWordFlag::Noun | KEduVocWordFlag::Feminine);
0468     noun->appendChildContainer(nounChild);
0469     nounChild = new KEduVocWordType(i18n("Neuter"), noun);
0470     nounChild->setWordType(KEduVocWordFlag::Noun | KEduVocWordFlag::Neuter);
0471     noun->appendChildContainer(nounChild);
0472 
0473     KEduVocWordType *verb = new KEduVocWordType(i18n("Verb"), root);
0474     verb->setWordType(KEduVocWordFlag::Verb);
0475     root->appendChildContainer(verb);
0476 
0477     KEduVocWordType *adjective = new KEduVocWordType(i18n("Adjective"), root);
0478     adjective->setWordType(KEduVocWordFlag::Adjective);
0479     root->appendChildContainer(adjective);
0480 
0481     KEduVocWordType *adverb = new KEduVocWordType(i18n("Adverb"), root);
0482     adverb->setWordType(KEduVocWordFlag::Adverb);
0483     root->appendChildContainer(adverb);
0484 
0485     KEduVocWordType *conjunction = new KEduVocWordType(i18n("Conjunction"), root);
0486     conjunction->setWordType(KEduVocWordFlag::Conjunction);
0487     root->appendChildContainer(conjunction);
0488 }
0489 
0490 void ParleyDocument::setDefaultDocumentProperties(KEduVocDocument *doc)
0491 {
0492     KEMailSettings emailSettings;
0493     emailSettings.setProfile(emailSettings.defaultProfileName());
0494     doc->setAuthor(emailSettings.getSetting(KEMailSettings::RealName));
0495     doc->setAuthorContact(emailSettings.getSetting(KEMailSettings::EmailAddress));
0496 
0497     doc->setLicense(i18n("Public Domain"));
0498     doc->setCategory(i18n("Languages"));
0499 
0500     QString locale = QLocale().name();
0501 
0502     doc->appendIdentifier();
0503     doc->appendIdentifier();
0504     doc->identifier(0).setName(QLocale(locale).nativeLanguageName());
0505     doc->identifier(0).setLocale(locale);
0506     doc->identifier(1).setName(i18n("A Second Language"));
0507     doc->identifier(1).setLocale(locale);
0508 
0509     KEduVocLesson *lesson = new KEduVocLesson(i18n("Lesson 1"), doc->lesson());
0510     doc->lesson()->appendChildContainer(lesson);
0511 
0512     // add some entries
0513     for (int i = 0; i < 15; i++) {
0514         lesson->appendEntry(new KEduVocExpression());
0515     }
0516 
0517     doc->setModified(false);
0518 }
0519 
0520 void ParleyDocument::slotGHNS(const QList<KNSCore::Entry> &entries)
0521 {
0522     QMimeDatabase db;
0523     QString fileName;
0524     int numberInstalled = 0;
0525     for (const auto &entry : entries) {
0526         if (entry.status() != KNS3::Entry::Installed) {
0527             continue;
0528         }
0529         ++numberInstalled;
0530         // check mime type and if kvtml, open it
0531         const QStringList installedFiles = entry.installedFiles();
0532         for (const QString &file : installedFiles) {
0533             QMimeType mimeType = db.mimeTypeForFile(file);
0534             qDebug() << "KNS2 file of mime type:" << db.mimeTypeForFile(file).name();
0535             if (mimeType.inherits(QStringLiteral("application/x-kvtml"))) {
0536                 ParleyMainWindow::instance()->addRecentFile(QUrl::fromLocalFile(file), QString()); ///@todo: title!
0537                 fileName = file;
0538             }
0539         }
0540     }
0541 
0542     // to enable the display in the welcome screen
0543     Prefs::self()->save();
0544     m_parleyApp->updateRecentFilesModel();
0545     if (numberInstalled > 1) {
0546         openGHNS();
0547     } else if (numberInstalled == 1) {
0548         if (open(QUrl::fromLocalFile(fileName)))
0549             m_parleyApp->showPracticeConfiguration();
0550         else
0551             KMessageBox::error(m_parleyApp, i18n("Could not open vocabulary collection \"%1\"", entries.first().name()));
0552     }
0553 }
0554 
0555 void ParleyDocument::documentProperties()
0556 {
0557     DocumentProperties *titleAuthorWidget = new DocumentProperties(m_doc.get(), false, m_parleyApp);
0558 
0559     QDialogButtonBox *button_dialog = new QDialogButtonBox;
0560     button_dialog->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
0561 
0562     QVBoxLayout *layout = new QVBoxLayout;
0563     layout->addWidget(titleAuthorWidget);
0564     layout->addWidget(button_dialog);
0565 
0566     QDialog *titleAuthorDialog = new QDialog;
0567     titleAuthorDialog->setLayout(layout);
0568     titleAuthorDialog->setWindowTitle(i18nc("@title:window document properties", "Properties for %1", m_doc->url().url()));
0569 
0570     // the language options are only shown, when this is used to create a new document.
0571     titleAuthorWidget->languageGroupBox->setVisible(false);
0572 
0573     connect(titleAuthorDialog, &QDialog::accepted, titleAuthorWidget, &DocumentProperties::accept);
0574     connect(button_dialog, &QDialogButtonBox::accepted, titleAuthorDialog, &QDialog::accept);
0575     connect(button_dialog, &QDialogButtonBox::rejected, titleAuthorDialog, &QDialog::reject);
0576 
0577     titleAuthorDialog->exec();
0578     delete titleAuthorDialog;
0579     Q_EMIT documentChanged(m_doc);
0580 }
0581 
0582 void ParleyDocument::languageProperties()
0583 {
0584     LanguageProperties properties(m_doc.get(), m_parleyApp);
0585     if (properties.exec() == QDialog::Accepted) {
0586         Q_EMIT languagesChanged();
0587     }
0588 }
0589 
0590 void ParleyDocument::exportDialog()
0591 {
0592 #ifdef HAVE_LIBXSLT
0593     ExportDialog dialog(this, m_parleyApp);
0594     dialog.exec();
0595 #endif
0596 }
0597 
0598 void ParleyDocument::slotFileMerge()
0599 {
0600     ///@todo as soon as some brave soul descends into the lib and implements merging this should be enabled
0601     //     KUrl url = KFileDialog::getOpenUrl(QString(), KEduVocDocument::pattern(KEduVocDocument::Reading), parentWidget(), i18n("Merge Vocabulary File"));
0602     //
0603     //     if (!url.isEmpty()) {
0604     //         QString msg = i18n("Loading %1", url.path());
0605     //         slotStatusMsg(msg);
0606     //
0607     //         KEduVocDocument *new_doc = new KEduVocDocument(this);
0608     //         new_doc->setCsvDelimiter(Prefs::separator());
0609     //         new_doc->open(url);
0610     //
0611     //         m_doc->merge(new_doc, true);
0612     //
0613     //         KEduVocWordFlag::setTenseNames(m_doc->tenseDescriptions());
0614     //         KVTUsage::setUsageNames(m_doc->usageDescriptions());
0615     //
0616     //         delete(new_doc);
0617     //         m_recentFilesAction->addUrl(url);
0618     //         m_tableModel->reset();
0619     //         m_lessonModel->setDocument(m_doc);
0620     //         m_tableView->adjustContent();
0621     //     }
0622 }
0623 
0624 void ParleyDocument::enableAutoBackup(bool enable)
0625 {
0626     if (!enable) {
0627         if (m_backupTimer) {
0628             m_backupTimer->stop();
0629         }
0630     } else {
0631         if (!m_backupTimer) {
0632             m_backupTimer = new QTimer(this);
0633             connect(m_backupTimer, &QTimer::timeout, this, &ParleyDocument::save);
0634         }
0635         m_backupTimer->start(Prefs::backupTime() * 60 * 1000);
0636     }
0637 }