LibKEduVocDocument

keduvocdocument.cpp
1/*
2 * Vocabulary Document for KDE Edu
3 * SPDX-FileCopyrightText: 1999-2001 Ewald Arnold <kvoctrain@ewald-arnold.de>
4 * SPDX-FileCopyrightText: 2005-2007 Peter Hedlund <peter.hedlund@kdemail.net>
5 * SPDX-FileCopyrightText: 2007 Frederik Gladhorn <frederik.gladhorn@kdemail.net>
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8#include "keduvocdocument.h"
9
10#include <QCoreApplication>
11#include <QFileInfo>
12#include <QIODevice>
13#include <QTemporaryFile>
14#include <QTextStream>
15#include <QtAlgorithms>
16
17#include <KAutoSaveFile>
18#include <KCompressionDevice>
19#include <KLazyLocalizedString>
20#include <KLocalizedString>
21#include <QDebug>
22#include <kio/filecopyjob.h>
23
24#include "keduvoccsvwriter.h"
25#include "keduvocexpression.h"
26#include "keduvockvtml2writer.h"
27#include "keduvocleitnerbox.h"
28#include "keduvoclesson.h"
29#include "keduvocwordtype.h"
30#include "readerwriters/readerbase.h"
31#include "readerwriters/readermanager.h"
32
33#define WQL_IDENT "WordQuiz"
34
35#define KVTML_EXT "kvtml"
36#define CSV_EXT "csv"
37#define TXT_EXT "txt"
38#define WQL_EXT "wql"
39
40/** @details Private Data class for KEduVocDocument */
41class KEduVocDocument::KEduVocDocumentPrivate
42{
43public:
44 /** constructor */
45 KEduVocDocumentPrivate(KEduVocDocument *qq)
46 : q(qq)
47 {
48 m_lessonContainer = nullptr;
49 m_wordTypeContainer = nullptr;
50 m_leitnerContainer = nullptr;
51 m_autosave = new KAutoSaveFile;
52 init();
53 }
54
55 /** destructor */
56 ~KEduVocDocumentPrivate();
57
58 /** initializer */
59 void init();
60
61 KEduVocDocument *q; ///< The Front End
62
63 /** autosave file used to provide locking access to the underlying file
64 * Note: It is a pointer to allow locking a new file, saving results and
65 * then transferring the lock to m_autosave without risking loss of lock.
66 * See saveAs for clarification*/
67 KAutoSaveFile *m_autosave;
68
69 bool m_dirty; ///< dirty bit
70 bool m_isReadOnly; ///< FileOpenReadOnly was used for opening
71
72 // save these to document
73 QList<KEduVocIdentifier> m_identifiers; ///< list of identifiers
74
75 QList<int> m_extraSizeHints; ///< unused
76 QList<int> m_sizeHints; ///< unused
77
78 QString m_generator; ///< name of generating application
79 QString m_queryorg; ///< unused
80 QString m_querytrans; ///< unused
81
82 QStringList m_tenseDescriptions; ///< unused. Was used in merge
83 QSet<QString> m_usages; ///< unused
84
85 QString m_title; ///< Document title
86 QString m_author; ///< Document author
87 QString m_authorContact; ///< Author contact information
88 QString m_license; ///< Document license
89 QString m_comment; ///< Document comment
90 QString m_version; ///< Document version
91 QString m_csvDelimiter; ///< CSV delimiter
92
93 /** Categories that can later be used to sork kvtml files:
94 * language, music, children, anatomy
95 */
96 QString m_category; ///< Document category
97
98 KEduVocLesson *m_lessonContainer; ///< Root lesson container
99 KEduVocWordType *m_wordTypeContainer; ///< Root word types container
100 /** Root Leitner container
101 * (probably unused) This is not used in Parley
102 * */
103 KEduVocLeitnerBox *m_leitnerContainer;
104
105 /** Creates an autosave file for fpath in order to lock the file
106 * @param autosave a reference to an allocated KAutosave
107 * @param fpath File path to the file to be locked
108 * @param flags Describes how to deal with locked file etc.
109 * @return ErrorCode where NoError is success
110 * */
111 KEduVocDocument::ErrorCode initializeKAutoSave(KAutoSaveFile &autosave, QString const &fpath, FileHandlingFlags flags) const;
112};
113
114KEduVocDocument::KEduVocDocumentPrivate::~KEduVocDocumentPrivate()
115{
116 delete m_lessonContainer;
117 delete m_wordTypeContainer;
118 delete m_leitnerContainer;
119 delete m_autosave;
120}
121
122void KEduVocDocument::KEduVocDocumentPrivate::init()
123{
124 delete m_lessonContainer;
125 m_lessonContainer = new KEduVocLesson(i18nc("The top level lesson which contains all other lessons of the document.", "Document Lesson"), q);
126 m_lessonContainer->setContainerType(KEduVocLesson::Lesson);
127 delete m_wordTypeContainer;
128 m_wordTypeContainer = new KEduVocWordType(i18n("Word types"));
129
130 delete m_leitnerContainer;
131 m_leitnerContainer = new KEduVocLeitnerBox(i18n("Leitner Box"));
132
133 m_tenseDescriptions.clear();
134 m_identifiers.clear();
135 m_extraSizeHints.clear();
136 m_sizeHints.clear();
137 m_dirty = false;
138 m_isReadOnly = false;
139 m_queryorg = QLatin1String("");
140 m_querytrans = QLatin1String("");
141 m_autosave->setManagedFile(QUrl());
142 m_author = QLatin1String("");
143 m_title = QLatin1String("");
144 m_comment = QLatin1String("");
145 m_version = QLatin1String("");
146 m_generator = QLatin1String("");
147 m_csvDelimiter = QString('\t');
148 m_usages.clear();
149 m_license.clear();
150 m_category.clear();
151}
152
154KEduVocDocument::KEduVocDocumentPrivate::initializeKAutoSave(KAutoSaveFile &autosave, QString const &fpath, FileHandlingFlags flags) const
155{
156 QList<KAutoSaveFile *> staleFiles = KAutoSaveFile::staleFiles(QUrl::fromLocalFile(fpath), QCoreApplication::instance()->applicationName());
157 if (!staleFiles.isEmpty()) {
158 if (flags & FileIgnoreLock) {
159 foreach (KAutoSaveFile *f, staleFiles) {
161 f->remove();
162 delete f;
163 }
164 } else {
165 qWarning() << i18n("Cannot lock file %1", fpath);
166 return FileLocked;
167 }
168 }
169
170 autosave.setManagedFile(QUrl::fromLocalFile(fpath));
171 if (!autosave.open(QIODevice::ReadWrite)) {
172 qWarning() << i18n("Cannot lock file %1", autosave.fileName());
173 return FileCannotLock;
174 }
175
176 return NoError;
177}
178
180 : QObject(parent)
181 , d(new KEduVocDocumentPrivate(this))
182{
183}
184
186{
187 delete d;
188}
189
191{
192 d->m_dirty = dirty;
193 Q_EMIT docModified(d->m_dirty);
194}
195
197{
198 KCompressionDevice f(fileName);
200
202
203 f.close();
204
205 return reader->fileTypeHandled();
206}
207
209{
210 // save csv delimiter to preserve it in case this is a csv document
211 QString csv = d->m_csvDelimiter;
212 // clear all other properties
213 d->init();
214 if (!url.isEmpty()) {
215 setUrl(url);
216 }
217 d->m_csvDelimiter = csv;
218
220 QString errorMessage = i18n("<qt>Cannot open file<br /><b>%1</b></qt>", url.toDisplayString());
221
222 QString temporaryFile;
223 QTemporaryFile tempFile;
224 if (url.isLocalFile()) {
225 temporaryFile = url.toLocalFile();
226 } else {
227 if (!tempFile.open()) {
228 qWarning() << i18n("Cannot open tempfile %1", tempFile.fileName());
229 return Unknown;
230 }
232 if (!job->exec()) {
233 qWarning() << i18n("Cannot download %1: %2", url.toDisplayString(), job->errorString());
234 return FileDoesNotExist;
235 }
236 temporaryFile = tempFile.fileName();
237 }
238
239 if (flags & FileOpenReadOnly) {
240 d->m_isReadOnly = true;
241 }
242
243 ErrorCode autosaveError = NoError;
244
245 if (!d->m_isReadOnly) {
246 autosaveError = d->initializeKAutoSave(*d->m_autosave, temporaryFile, flags);
247 if (autosaveError != NoError) {
248 return autosaveError;
249 }
250 }
251
252 KCompressionDevice f(temporaryFile);
253 if (f.open(QIODevice::ReadOnly)) {
255 errStatus = reader->read(*this);
256
257 if (errStatus != KEduVocDocument::NoError) {
258 errorMessage = i18n("Could not open or properly read \"%1\"\n(Error reported: %2)", url.toDisplayString(), reader->errorMessage());
259 }
260 } else {
261 errStatus = FileCannotRead;
262 }
263
264 f.close();
265
266 if (errStatus == KEduVocDocument::NoError) {
267 setModified(false);
268 } else {
269 qWarning() << errorMessage;
270 }
271
272 return errStatus;
273}
274
276{
277 if (!d->m_isReadOnly) {
278 d->m_autosave->releaseLock();
279 }
280}
281
283{
284 if (d->m_isReadOnly) {
285 return FileIsReadOnly;
286 }
287
288 QUrl tmp(url);
289
290 if (ft == Automatic) {
291 if (tmp.path().right(strlen("." KVTML_EXT)) == "." KVTML_EXT)
292 ft = Kvtml;
293 else if (tmp.path().right(strlen("." CSV_EXT)) == "." CSV_EXT)
294 ft = Csv;
295 else {
296 return FileTypeUnknown;
297 }
298 }
299
300 QString errorMessage = i18n("Cannot write to file %1", tmp.toDisplayString());
301
302 KAutoSaveFile *autosave;
303
304 // If we don't care about the lock always create a new one
305 // If we are changing files create a new lock
306 if ((flags & FileIgnoreLock) || (d->m_autosave->managedFile() != tmp)) {
307 autosave = new KAutoSaveFile;
308 ErrorCode autosaveError = d->initializeKAutoSave(*autosave, tmp.toLocalFile(), flags);
309 if (autosaveError != NoError) {
310 delete autosave;
311 return autosaveError;
312 }
313 }
314
315 // We care about the lock and we think we still have it.
316 else {
317 autosave = d->m_autosave;
318 // Is the lock still good?
319 if (!autosave->exists()) {
320 return FileCannotLock;
321 }
322 }
323
324 QFile f(tmp.toLocalFile());
325 if (!f.open(QIODevice::WriteOnly)) {
326 qCritical() << i18n("Cannot write to file %1", f.fileName());
327 return FileCannotWrite;
328 }
329
330 bool saved = false;
331
332 switch (ft) {
333 case Kvtml: {
334 // write version 2 file
335 KEduVocKvtml2Writer kvtmlWriter(&f);
336 saved = kvtmlWriter.writeDoc(this, d->m_generator);
337 } break;
338 ///@todo port me
339 // case Kvtml1: {
340 // // write old version 1 file
341 // KEduVocKvtmlWriter kvtmlWriter( &f );
342 // saved = kvtmlWriter.writeDoc( this, d->m_generator );
343 // }
344 // break;
345 case Csv: {
346 KEduVocCsvWriter csvWriter(&f);
347 saved = csvWriter.writeDoc(this, d->m_generator);
348 } break;
349 default: {
350 qCritical() << "kvcotrainDoc::saveAs(): unknown filetype";
351 } break;
352 } // switch
353
354 f.close();
355
356 if (!saved) {
357 qCritical() << "Error Saving File" << tmp.toDisplayString();
358
359 if (autosave != d->m_autosave) {
360 delete autosave;
361 }
362 return FileWriterFailed;
363 }
364
365 if (autosave != d->m_autosave) {
366 // The order is important: release old lock, delete old locker and then claim new locker.
367 d->m_autosave->releaseLock();
368 delete d->m_autosave;
369 d->m_autosave = autosave;
370 }
371
372 setModified(false);
373 return NoError;
374}
375
377{
378 // no file needed
379 KEduVocKvtml2Writer kvtmlWriter(nullptr);
380 return kvtmlWriter.toByteArray(this, generator);
381}
382
383void KEduVocDocument::merge(KEduVocDocument *docToMerge, bool matchIdentifiers)
384{
385 Q_UNUSED(docToMerge)
386 Q_UNUSED(matchIdentifiers)
387 qDebug() << "Merging of docs is not implemented"; /// @todo IMPLEMENT ME
388 // This code was really horribly broken.
389 // Now with the new classes we could attempt to reactivate it.
390 // A rewrite might be easier.
391
392 /*
393 if (docToMerge) {
394
395 QStringList new_names = docToMerge->lessonDescriptions();
396
397 QStringList new_types = docToMerge->typeDescriptions();
398
399 QStringList new_tenses = docToMerge->tenseDescriptions();
400
401 QList<int> old_in_query = lessonsInPractice();
402 QList<int> new_in_query = docToMerge->lessonsInPractice();
403
404 QStringList new_usages = docToMerge->usageDescriptions();
405
406 int lesson_offset = d->m_lessonDescriptions.count();
407 for (int i = 0; i < new_names.count(); i++) {
408 d->m_lessonDescriptions.append(new_names[i]);
409 }
410
411 for (int i = 0; i < new_in_query.count(); i++)
412 old_in_query.append(new_in_query[i] + lesson_offset);
413 setLessonsInPractice(old_in_query);
414
415 int types_offset = d->m_typeDescriptions.count();
416 for (int i = 0; i < new_types.count(); i++) {
417 d->m_typeDescriptions.append(new_types[i]);
418 }
419
420 int tenses_offset = d->m_tenseDescriptions.count();
421 for (int i = 0; i < new_tenses.count(); i++) {
422 d->m_tenseDescriptions.append(new_tenses[i]);
423 }
424
425 int usages_offset = d->m_usageDescriptions.count();
426 for (int i = 0; i < new_usages.count(); i++) {
427 d->m_usageDescriptions.append(new_usages[i]);
428 }
429
430 bool equal = true;
431 if (originalIdentifier() != docToMerge->originalIdentifier())
432 equal = false;
433 for (int i = 1; i < identifierCount(); i++)
434 if (identifier(i) != docToMerge->identifier(i))
435 equal = false;
436
437 if (!matchIdentifiers)
438 equal = true; ///@todo massive cheating, problem if docToMerge has more identifiers than this
439
440 if (equal) { // easy way: same language codes, just append
441
442 for (int i = 0; i < docToMerge->entryCount(); i++) {
443 KEduVocExpression *expr = docToMerge->entry(i);
444
445 expr->setLesson(expr->lesson() + lesson_offset);
446
447 for (int lang = 0; lang <= expr->translationCount(); lang++) {
448 QString t = expr->translation(lang).type();
449 // adjust type offset
450 if (!t.isEmpty() && t.left(1) == QM_USER_TYPE) {
451 QString t2;
452 t.remove(0, 1);
453 t2.setNum(t.toInt() + types_offset);
454 t2.prepend(QM_USER_TYPE);
455 expr->translation(lang).setType (t2);
456 }
457
458 t = expr->translation(lang).usageLabel();
459 // adjust usage offset
460 QString tg;
461 if (!t.isEmpty()) {
462 QString t2;
463 while (t.left(strlen(":")) == UL_USER_USAGE) {
464 QString n;
465 t.remove(0, 1);
466 int next;
467 if ((next = t.indexOf(":")) >= 0) {
468 n = t.left(next);
469 t.remove(0, next + 1);
470 }
471 else {
472 n = t;
473 t = "";
474 }
475
476 t2.setNum(n.toInt() + usages_offset);
477 t2.prepend(UL_USER_USAGE);
478 if (tg.length() == 0)
479 tg = t2;
480 else
481 tg += ':' + t2;
482 }
483
484 if (tg.length() == 0)
485 tg = t;
486 else if (t.length() != 0)
487 tg += ':' + t;
488
489 expr->translation(lang).setUsageLabel (tg);
490 }
491
492 KEduVocConjugation conj = expr->translation(lang).conjugation();
493 bool condirty = false;
494 for (int ci = 0; ci < conj.entryCount(); ci++) {
495 t = conj.getType(ci);
496 if (!t.isEmpty() && t.left(1) == UL_USER_TENSE) {
497 t.remove(0, strlen(UL_USER_TENSE));
498 QString t2;
499 t2.setNum(t.toInt() + tenses_offset);
500 t2.prepend(UL_USER_TENSE);
501 conj.setType(ci, t2);
502 condirty = true;
503 }
504 if (condirty)
505 expr->translation(lang).setConjugation(conj);
506 }
507 }
508
509 appendEntry(expr);
510 }
511 setModified();
512 }
513 else { // hard way: move entries around, most attributes get lost
514 QList<int> move_matrix;
515 QList<bool> cs_equal;
516 QString s;
517
518 for (int i = 0; i < qMax (identifierCount(), docToMerge->identifierCount()); i++)
519 cs_equal.append(false);
520
521 move_matrix.append(docToMerge->indexOfIdentifier(originalIdentifier()));
522 for (int i = 1; i < identifierCount(); i++)
523 move_matrix.append(docToMerge->indexOfIdentifier(identifier(i)));
524
525 for (int j = 0; j < docToMerge->entryCount(); j++) {
526 KEduVocExpression new_expr;
527 KEduVocExpression *expr = docToMerge->entry(j);
528 new_expr.setLesson(expr->lesson()+lesson_offset);
529
530 for (int i = 0; i < move_matrix.count(); i++) {
531 int lpos = move_matrix[i];
532 if (lpos >= 0) {
533
534 if (lpos == 0)
535 s = expr->original();
536 else
537 s = expr->translation(lpos);
538
539 if (!cs_equal[lpos]) {
540 cs_equal[lpos] = true;
541 QString id = lpos == 0 ? originalIdentifier() : identifier(lpos);
542 }
543
544 if (i == 0)
545 new_expr.setOriginal(s);
546 else
547 new_expr.setTranslation(i, s);
548 QString r = expr->remark(lpos);
549 new_expr.setRemark (i, r);
550
551 QString t = expr->type(lpos);
552 if (!t.isEmpty() && t.left(1) == QM_USER_TYPE) {
553 QString t2;
554 t.remove(0, 1);
555 t2.setNum(t.toInt() + types_offset);
556 t2.prepend(QM_USER_TYPE);
557 new_expr.setType(i, t2);
558 }
559
560 t = expr->usageLabel(lpos);
561 if (!t.isEmpty() && t.left(1) == QM_USER_TYPE) {
562 QString t2;
563 t.remove(0, 1);
564 t2.setNum(t.toInt() + usages_offset);
565 t2.prepend(QM_USER_TYPE);
566 new_expr.setUsageLabel(i, t2);
567 }
568
569 KEduVocConjugation conj = expr->conjugation(lpos);
570 for (int ci = 0; ci < conj.entryCount(); ci++) {
571 t = conj.getType(ci);
572 if (!t.isEmpty() && t.left(1) == QM_USER_TYPE) {
573 t.remove (0, strlen(QM_USER_TYPE));
574 QString t2;
575 t2.setNum(t.toInt() + tenses_offset);
576 t2.prepend(QM_USER_TYPE);
577 conj.setType(ci, t2);
578 }
579 }
580
581 }
582 }
583 // only append if entries are used
584 bool used = !new_expr.original().isEmpty();
585 for (int i = 1; i < identifierCount(); i++)
586 if (!new_expr.translation(i).isEmpty())
587 used = true;
588
589 if (used) {
590 appendEntry(&new_expr);
591 setModified();
592 }
593 }
594 }
595 }
596 */
597}
598
600{
601 if (index < 0 || index >= d->m_identifiers.size()) {
602 qCritical() << " Error: Invalid identifier index: " << index;
603 }
604 return d->m_identifiers[index];
605}
606
608{
609 if (index < 0 || index >= d->m_identifiers.size()) {
610 qCritical() << " Error: Invalid identifier index: " << index;
611 }
612 return d->m_identifiers[index];
613}
614
616{
617 if (idx >= 0 && idx < d->m_identifiers.size()) {
618 d->m_identifiers[idx] = id;
619 }
620 setModified(true);
621}
622
623// works if const is removed
625{
626 for (int i = 0; i < identifierCount(); i++)
627 if (identifier(i).locale() == name)
628 return i;
629 return -1;
630}
631
633{
634 if (index < d->m_identifiers.size() && index >= 0) {
635 d->m_identifiers.removeAt(index);
636 d->m_lessonContainer->removeTranslation(index);
637 }
638}
639
641{
642 return d->m_dirty;
643}
644
646{
647 return d->m_identifiers.count(); // number of translations
648}
649
651{
652 int i = d->m_identifiers.size();
653 // qDebug() << "appendIdentifier: " << i << id.name() << id.locale();
654 d->m_identifiers.append(id);
655 if (id.name().isEmpty()) {
656 if (i == 0) {
657 identifier(i).setName(i18nc("The name of the first language/column of vocabulary, if we have to guess it.", "Original"));
658 } else {
659 identifier(i).setName(i18nc("The name of the second, third ... language/column of vocabulary, if we have to guess it.", "Translation %1", i));
660 }
661 }
662
663 return i;
664}
665
667{
668 return d->m_lessonContainer;
669}
670
672{
673 return d->m_wordTypeContainer;
674}
675
677{
678 return d->m_leitnerContainer;
679}
680
682{
683 return d->m_autosave->managedFile();
684}
685
687{
688 d->m_autosave->setManagedFile(url);
689}
690
692{
693 if (d->m_title.isEmpty())
694 return d->m_autosave->managedFile().fileName();
695 else
696 return d->m_title;
697}
698
700{
701 d->m_title = title;
702 ///@todo decouple document title and root lesson title
703 d->m_lessonContainer->setName(title);
704 setModified(true);
705}
706
708{
709 return d->m_author;
710}
711
713{
714 d->m_author = s.simplified();
715 setModified(true);
716}
717
719{
720 return d->m_authorContact;
721}
722
724{
725 d->m_authorContact = s.simplified();
726 setModified(true);
727}
728
730{
731 return d->m_license;
732}
733
735{
736 return d->m_comment;
737}
738
740{
741 d->m_category = category;
742 setModified(true);
743}
744
746{
747 return d->m_category;
748 ///@todo make writer/reader use this
749}
750
752{
753 org = d->m_queryorg;
754 trans = d->m_querytrans;
755}
756
758{
759 d->m_queryorg = org;
760 d->m_querytrans = trans;
761 setModified(true);
762}
763
765{
766 d->m_license = s.simplified();
767 setModified(true);
768}
769
771{
772 d->m_comment = s.trimmed();
773 setModified(true);
774}
775
777{
778 d->m_generator = generator;
779 setModified(true);
780}
781
783{
784 return d->m_generator;
785}
786
788{
789 return d->m_version;
790}
791
793{
794 d->m_version = vers;
795 setModified(true);
796}
797
799{
800 return d->m_csvDelimiter;
801}
802
804{
805 d->m_csvDelimiter = delimiter;
806 setModified(true);
807}
808
810{
811 static const struct SupportedFilter {
812 bool reading;
813 bool writing;
814 const char *extensions;
815 const KLazyLocalizedString description;
816 } filters[] = {{true, true, "*.kvtml", kli18n("KDE Vocabulary Document")},
817 {true, false, "*.wql", kli18n("KWordQuiz Document")},
818 {true, false, "*.xml.qz *.pau.gz", kli18n("Pauker Lesson")},
819 {true, false, "*.voc", kli18n("Vokabeltrainer")},
820 {true, false, "*.xdxf", kli18n("XML Dictionary Exchange Format")},
821 {true, true, "*.csv", kli18n("Comma Separated Values (CSV)")},
822 // last is marker for the end, do not remove it
823 {false, false, nullptr, KLazyLocalizedString()}};
824 QStringList newfilters;
825 QStringList allext;
826 for (int i = 0; filters[i].extensions; ++i) {
827 if ((mode == Reading && filters[i].reading) || (mode == Writing && filters[i].writing)) {
828 newfilters.append(KLocalizedString(filters[i].description).toString() + " (" + QLatin1String(filters[i].extensions) + ')');
829 allext.append(QLatin1String(filters[i].extensions));
830 }
831 }
832 if (mode == Reading) {
833 newfilters.prepend(allext.join(QLatin1Char(' ')) + '|' + i18n("All supported documents"));
834 }
835 return newfilters.join(QLatin1String(";;"));
836}
837
839{
840 switch (errorCode) {
841 case NoError:
842 return i18n("No error found.");
843
844 case InvalidXml:
845 return i18n("Invalid XML in document.");
846 case FileTypeUnknown:
847 return i18n("Unknown file type.");
848 case FileCannotWrite:
849 return i18n("File is not writeable.");
850 case FileWriterFailed:
851 return i18n("File writer failed.");
852 case FileCannotRead:
853 return i18n("File is not readable.");
854 case FileReaderFailed:
855 return i18n("The file reader failed.");
856 case FileDoesNotExist:
857 return i18n("The file does not exist.");
858 case FileLocked:
859 return i18n("The file is locked by another process.");
860 case FileCannotLock:
861 return i18n("The lock file can't be created.");
862 case Unknown:
863 default:
864 return i18n("Unknown error.");
865 }
866}
867
868#include "moc_keduvocdocument.cpp"
bool open(OpenMode openmode) override
void setManagedFile(const QUrl &filename)
static QList< KAutoSaveFile * > staleFiles(const QUrl &url, const QString &applicationName=QString())
void close() override
bool open(QIODevice::OpenMode mode) override
ErrorCode saveAs(const QUrl &url, FileType ft, FileHandlingFlags flags=FileDefaultHandling)
Saves the data under the given name.
FileHandlingFlags
indicates file open/save status locking or readonly
@ FileIgnoreLock
Ignore the file lock.
@ FileOpenReadOnly
Open without any intention to change and save back later. This also implies FileIgnoreLock.
void setGenerator(const QString &generator)
Sets the generator of the file.
void setCsvDelimiter(const QString &delimiter)
Sets the delimiter (separator) used for csv import and export.
int appendIdentifier(const KEduVocIdentifier &identifier=KEduVocIdentifier())
Appends a new identifier (usually a language)
int identifierCount() const
void setTitle(const QString &title)
Set the title of the file.
void setDocumentComment(const QString &comment)
Set the comment of the file.
static QString pattern(FileDialogMode mode)
Create a string with the supported document types, that can be used as filter in KFileDialog.
QString license() const
KEDUVOCDOCUMENT_DEPRECATED void setQueryIdentifier(const QString &org, const QString &trans)
Sets the identifiers for the current query not written in the new version!
QString documentComment() const
static QString errorDescription(int errorCode)
Returns a QString description of the errorCode.
~KEduVocDocument() override
Destructor.
static FileType detectFileType(const QString &fileName)
void setAuthor(const QString &author)
Set the author of the file.
void setModified(bool dirty=true)
Indicates if the document is modified.
bool isModified() const
void merge(KEduVocDocument *docToMerge, bool matchIdentifiers)
Merges data from another document (UNIMPLEMENTED)
void docModified(bool mod)
Emitted when the document becomes modified or saved.
KEduVocWordType * wordTypeContainer()
Returns the root word type object.
int indexOfIdentifier(const QString &name) const
Determines the index of a given identifier.
KEDUVOCDOCUMENT_DEPRECATED void queryIdentifier(QString &org, QString &trans) const
Retrieves the identifiers for the current query not written in the new version!
KEduVocLesson * lesson()
Get the lesson root object.
void setUrl(const QUrl &url)
Sets the URL of the XML file.
ErrorCode
the return code when opening/saving
@ FileIsReadOnly
Can't save this file because it was opened read-only.
@ FileCannotWrite
unwritable file
@ FileCannotLock
Can't create an autosave file for this document.
@ InvalidXml
malformed xml or bad file formatting
@ Unknown
unspecified error
@ FileWriterFailed
file writer failed
@ FileTypeUnknown
unknown file type
@ FileReaderFailed
file reader failed
@ FileDoesNotExist
unknown file type
@ FileCannotRead
unreadable file
@ FileLocked
An autosave file exists for this document.
KEduVocDocument(QObject *parent=nullptr)
Constructor for a KDEEdu vocabulary document.
KEduVocLeitnerBox * leitnerContainer()
Returns the root Leitner container.
QString author() const
QString title() const
QByteArray toByteArray(const QString &generator)
KEduVocIdentifier & identifier(int index)
Returns the identifier of translation index.
QString csvDelimiter() const
Returns the delimiter (separator) used for csv import and export.
void setLicense(const QString &license)
Set the license of the file.
ErrorCode open(const QUrl &url, FileHandlingFlags flags=FileDefaultHandling)
Opens and locks a document file.
void setCategory(const QString &category)
Set the category of the file.
QString authorContact() const
void setIdentifier(int index, const KEduVocIdentifier &lang)
Sets the identifier of translation.
FileType
known vocabulary file types
@ Kvtml
Kvtml 2.0.
@ Csv
Command separated values.
@ Automatic
try to automatically determine file type
QString generator() const
void setAuthorContact(const QString &authorContact)
Set the author contact info.
FileDialogMode
used as parameter for pattern
QString category() const
void close()
Close a document file and release the lock on the file.
void removeIdentifier(int index)
Removes identifier and the according translation in all entries.
QString version() const
void setVersion(const QString &ver)
Sets version of the loaded file.
Class to store meta information about a language or any other category in the vocabulary.
void setName(const QString &name)
Set the name.
Class to write kvtml2 data files from KEduVocDocument.
Leitner Boxes are an alternative grading system.
class to store information about a lesson
class to store translation word types
QString errorString() const override
static ReaderPtr reader(QIODevice &device)
returns a reader that can read this device.
QSharedPointer< ReaderBase > ReaderPtr
a QSharedPointer to the ReaderBase class.
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
KIOCORE_EXPORT FileCopyJob * file_copy(const QUrl &src, const QUrl &dest, int permissions=-1, JobFlags flags=DefaultFlags)
QCoreApplication * instance()
bool exists(const QString &fileName)
virtual QString fileName() const const override
bool open(FILE *fh, OpenMode mode, FileHandleFlags handleFlags)
bool remove()
virtual void close() override
void append(QList< T > &&value)
bool isEmpty() const const
void prepend(parameter_type value)
QObject(QObject *parent)
Q_EMITQ_EMIT
QObject * parent() const const
QString right(qsizetype n) const const
QString simplified() const const
QString trimmed() const const
QString join(QChar separator) const const
virtual QString fileName() const const override
QUrl fromLocalFile(const QString &localFile)
QString path(ComponentFormattingOptions options) const const
QString toDisplayString(FormattingOptions options) const const
QString toLocalFile() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri Feb 21 2025 11:49:27 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.