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{
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
virtual void releaseLock()
QUrl managedFile() const
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
void setName(const QString &name)
set the container name
void removeTranslation(int translation)
Removes a translation.
The primary entry point to the hierarchy of objects describing vocabularies.
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.
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)
qsizetype count() const const
bool isEmpty() const const
void prepend(parameter_type value)
void removeAt(qsizetype i)
qsizetype size() const const
Q_EMITQ_EMIT
QObject * parent() const const
bool isEmpty() 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
QString fileName(ComponentFormattingOptions options) const const
QUrl fromLocalFile(const QString &localFile)
bool isEmpty() const const
bool isLocalFile() const const
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-2024 The KDE developers.
Generated on Fri Dec 20 2024 11:49:40 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.