00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "keduvocdocument.h"
00020
00021 #include <QtCore/QFileInfo>
00022 #include <QtCore/QTextStream>
00023 #include <QtCore/QtAlgorithms>
00024 #include <QtCore/QIODevice>
00025
00026 #include <klocale.h>
00027 #include <kdebug.h>
00028 #include <kio/netaccess.h>
00029 #include <krandomsequence.h>
00030 #include <kfilterdev.h>
00031
00032 #include "keduvocexpression.h"
00033 #include "keduvoclesson.h"
00034 #include "keduvocwordtype.h"
00035 #include "keduvockvtmlwriter.h"
00036 #include "keduvockvtml2writer.h"
00037 #include "keduvoccsvreader.h"
00038 #include "keduvoccsvwriter.h"
00039 #include "keduvockvtml2reader.h"
00040 #include "keduvocwqlreader.h"
00041 #include "keduvocpaukerreader.h"
00042 #include "keduvocvokabelnreader.h"
00043 #include "keduvocxdxfreader.h"
00044
00045 #define WQL_IDENT "WordQuiz"
00046
00047 #define KVTML_EXT "kvtml"
00048 #define CSV_EXT "csv"
00049 #define TXT_EXT "txt"
00050 #define WQL_EXT "wql"
00051
00052 class KEduVocDocument::KEduVocDocumentPrivate
00053 {
00054 public:
00055 KEduVocDocumentPrivate( KEduVocDocument* qq )
00056 : q( qq )
00057 {
00058 init();
00059 }
00060
00061 ~KEduVocDocumentPrivate();
00062
00063 void init();
00064
00065 KEduVocDocument* q;
00066
00067 bool m_dirty;
00068 KUrl m_url;
00069
00070
00071 QList<KEduVocIdentifier> m_identifiers;
00072
00073 int m_currentLesson;
00074 QList<int> m_extraSizeHints;
00075 QList<int> m_sizeHints;
00076
00077 QString m_generator;
00078 QString m_queryorg;
00079 QString m_querytrans;
00080 QList<KEduVocExpression> m_vocabulary;
00081
00082 QStringList m_tenseDescriptions;
00083 QSet<QString> m_usages;
00084 QString m_title;
00085 QString m_author;
00086 QString m_license;
00087 QString m_comment;
00088 QString m_version;
00089 QString m_csvDelimiter;
00090
00094 QString m_category;
00095
00096
00097 QList<KEduVocLesson> m_lessons;
00098
00099 KEduVocWordType m_wordTypes;
00100 };
00101
00102 KEduVocDocument::KEduVocDocumentPrivate::~KEduVocDocumentPrivate()
00103 {
00104 }
00105
00106 void KEduVocDocument::KEduVocDocumentPrivate::init()
00107 {
00108 m_lessons.clear();
00109 m_tenseDescriptions.clear();
00110 m_identifiers.clear();
00111 m_wordTypes.clear();
00112 m_extraSizeHints.clear();
00113 m_sizeHints.clear();
00114 m_vocabulary.clear();
00115 m_dirty = false;
00116 m_currentLesson = 0;
00117 m_queryorg = "";
00118 m_querytrans = "";
00119 m_url.setFileName( i18n( "Untitled" ) );
00120 m_title = "";
00121 m_author = "";
00122 m_comment = "";
00123 m_version = "";
00124 m_generator = "";
00125 m_csvDelimiter = QString( '\t' );
00126 m_usages.clear();
00127 m_license.clear();
00128 m_category.clear();
00129 }
00130
00131
00132 KEduVocDocument::KEduVocDocument( QObject *parent )
00133 : QObject( parent ), d( new KEduVocDocumentPrivate( this ) )
00134 {}
00135
00136
00137 KEduVocDocument::~KEduVocDocument()
00138 {
00139 delete d;
00140 }
00141
00142
00143 void KEduVocDocument::setModified( bool dirty )
00144 {
00145 d->m_dirty = dirty;
00146 emit docModified( d->m_dirty );
00147 }
00148
00149
00150 void KEduVocDocument::appendEntry( KEduVocExpression *expression )
00151 {
00152 insertEntry(expression, d->m_vocabulary.count());
00153 }
00154
00155
00156 void KEduVocDocument::insertEntry( KEduVocExpression *expression, int index )
00157 {
00158 d->m_vocabulary.insert( index, *expression );
00159
00160
00161 for (int i = 0; i < d->m_lessons.size(); ++i)
00162 {
00163 d->m_lessons[i].incrementEntriesAbove(index);
00164 }
00165
00166 if ( expression->lesson() >= 0 && expression->lesson() < d->m_lessons.count() ) {
00167 d->m_lessons[expression->lesson()].addEntry(index);
00168 }
00169 setModified();
00170 }
00171
00172
00173 KEduVocDocument::FileType KEduVocDocument::detectFileType( const QString &fileName )
00174 {
00175 QIODevice * f = KFilterDev::deviceForFile( fileName );
00176 if ( !f->open( QIODevice::ReadOnly ) ) {
00177 kDebug(1100) << "Warning, could not open QIODevice for file: " << fileName;
00178 delete f;
00179 return Csv;
00180 }
00181
00182 QTextStream ts( f );
00183 QString line1;
00184 QString line2;
00185
00186 line1 = ts.readLine();
00187 if ( !ts.atEnd() ) {
00188 line2 = ts.readLine();
00189 }
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208 QString tmp;
00209
00210 if ( line1.startsWith(QChar::fromLatin1('"'))) {
00211 ts.seek(0);
00212 tmp = ts.readLine();
00213
00214 for ( int x=0; x < 10; x++) {
00215 if (tmp.contains( "\"," )) {
00216 tmp = ts.readLine();
00217 if (tmp.endsWith('0')) {
00218 f->close();
00219 delete f;
00220 return Vokabeln;
00221 }
00222 }
00223 tmp = ts.readLine();
00224 }
00225 }
00226 f->close();
00227 delete f;
00228
00229
00230 if ( line1.startsWith(QString::fromLatin1("<?xml")) ) {
00231 if ( line2.indexOf( "pauker", 0 ) > 0 ) {
00232 return Pauker;
00233 }
00234 if ( line2.indexOf( "xdxf", 0 ) > 0 ) {
00235 return Xdxf;
00236 } else {
00237 return Kvtml;
00238 }
00239 }
00240
00241 if ( line1 == WQL_IDENT ) {
00242 return Wql;
00243 }
00244
00245 return Csv;
00246 }
00247
00248
00249 int KEduVocDocument::open( const KUrl& url )
00250 {
00251 d->init();
00252 if ( !url.isEmpty() ) {
00253 d->m_url = url;
00254 }
00255
00256 bool read = false;
00257 QString errorMessage = i18n( "<qt>Cannot open file<br /><b>%1</b></qt>", url.path() );
00258 QString temporaryFile;
00259 if ( KIO::NetAccess::download( url, temporaryFile, 0 ) ) {
00260 QIODevice * f = KFilterDev::deviceForFile( temporaryFile );
00261
00262 if ( !f->open( QIODevice::ReadOnly ) ) {
00263 kError() << errorMessage;
00264 return FileCannotRead;
00265 }
00266
00267 FileType ft = detectFileType( temporaryFile );
00268
00269 switch ( ft ) {
00270 case Kvtml: {
00271 kDebug(1100) << "Reading KVTML document...";
00272 KEduVocKvtml2Reader kvtmlReader( f );
00273 read = kvtmlReader.readDoc( this );
00274 if ( !read ) {
00275 errorMessage = kvtmlReader.errorMessage();
00276 }
00277 }
00278 break;
00279
00280 case Wql: {
00281 kDebug(1100) << "Reading WordQuiz (WQL) document...";
00282 KEduVocWqlReader wqlReader( f );
00283 d->m_url.setFileName( i18n( "Untitled" ) );
00284 read = wqlReader.readDoc( this );
00285 if ( !read ) {
00286 errorMessage = wqlReader.errorMessage();
00287 }
00288 }
00289 break;
00290
00291 case Pauker: {
00292 kDebug(1100) << "Reading Pauker document...";
00293 KEduVocPaukerReader paukerReader( this );
00294 d->m_url.setFileName( i18n( "Untitled" ) );
00295 read = paukerReader.read( f );
00296 if ( !read ) {
00297 errorMessage = i18n( "Parse error at line %1, column %2:\n%3", paukerReader.lineNumber(), paukerReader.columnNumber(), paukerReader.errorString() );
00298 }
00299 }
00300 break;
00301
00302 case Vokabeln: {
00303 kDebug(1100) << "Reading Vokabeln document...";
00304 KEduVocVokabelnReader vokabelnReader( f );
00305 d->m_url.setFileName( i18n( "Untitled" ) );
00306 read = vokabelnReader.readDoc( this );
00307 if ( !read ) {
00308 errorMessage = vokabelnReader.errorMessage();
00309 }
00310 }
00311 break;
00312
00313 case Csv: {
00314 kDebug(1100) << "Reading CVS document...";
00315 KEduVocCsvReader csvReader( f );
00316 read = csvReader.readDoc( this );
00317 if ( !read ) {
00318 errorMessage = csvReader.errorMessage();
00319 }
00320 }
00321 break;
00322
00323 case Xdxf: {
00324 kDebug(1100) << "Reading XDXF document...";
00325 KEduVocXdxfReader xdxfReader( this );
00326 d->m_url.setFileName( i18n( "Untitled" ) );
00327 read = xdxfReader.read( f );
00328 if ( !read ) {
00329 errorMessage = i18n( "Parse error at line %1, column %2:\n%3", xdxfReader.lineNumber(), xdxfReader.columnNumber(), xdxfReader.errorString() );
00330 }
00331 }
00332 break;
00333
00334 default: {
00335 kDebug(1100) << "Reading KVTML document (fallback)...";
00336 KEduVocKvtml2Reader kvtmlReader( f );
00337 read = kvtmlReader.readDoc( this );
00338 if ( !read ) {
00339 errorMessage = kvtmlReader.errorMessage();
00340 }
00341 }
00342 }
00343
00344 if ( !read ) {
00345 QString msg = i18n( "Could not open or properly read \"%1\"\n(Error reported: %2)", url.path(), errorMessage );
00346 kError() << msg << i18n( "Error Opening File" );
00348 return FileReaderFailed;
00349 }
00350
00351 f->close();
00352 delete f;
00353 KIO::NetAccess::removeTempFile( temporaryFile );
00354 }
00355
00356
00357 int defaultLessonNumber = appendLesson(i18n("Default Lesson"));
00358
00359 for (int i = 0; i < entryCount(); ++i)
00360 {
00361 if (entry(i)->lesson() == -1)
00362 {
00363 entry(i)->setLesson(defaultLessonNumber);
00364 lesson(defaultLessonNumber).addEntry(i);
00365 }
00366 }
00367 if (lesson(defaultLessonNumber).entries().size() == 0)
00368 {
00369 removeLesson(defaultLessonNumber, DeleteEmptyLesson);
00370 }
00371
00372 if ( !read ) {
00373 return FileReaderFailed;
00374 }
00375
00376 return 0;
00377 }
00378
00379
00380 int KEduVocDocument::saveAs( const KUrl & url, FileType ft, const QString & generator )
00381 {
00382 KUrl tmp( url );
00383
00384 if ( ft == Automatic ) {
00385 if ( tmp.path().right( strlen( "." KVTML_EXT ) ) == "." KVTML_EXT )
00386 ft = Kvtml;
00387 else if ( tmp.path().right( strlen( "." CSV_EXT ) ) == "." CSV_EXT )
00388 ft = Csv;
00389 else {
00390 return FileTypeUnknown;
00391 }
00392 }
00393
00394 QFile f( tmp.path() );
00395
00396 if ( !f.open( QIODevice::WriteOnly ) ) {
00397 kError() << i18n( "Cannot write to file %1", tmp.path() );
00398 return FileCannotWrite;
00399 }
00400
00401 bool saved = false;
00402
00403 switch ( ft ) {
00404 case Kvtml: {
00405
00406 KEduVocKvtml2Writer kvtmlWriter( &f );
00407 saved = kvtmlWriter.writeDoc( this, generator );
00408 }
00409 break;
00410 case Kvtml1: {
00411
00412 KEduVocKvtmlWriter kvtmlWriter( &f );
00413 saved = kvtmlWriter.writeDoc( this, generator );
00414 }
00415 break;
00416 case Csv: {
00417 KEduVocCsvWriter csvWriter( &f );
00418 saved = csvWriter.writeDoc( this, generator );
00419 }
00420 break;
00421 default: {
00422 kError() << "kvcotrainDoc::saveAs(): unknown filetype" << endl;
00423 }
00424 break;
00425 }
00426
00427 f.close();
00428
00429 if ( !saved ) {
00430 kError() << "Error Saving File" << tmp.path();
00431 return FileWriterFailed;
00432 }
00433
00434 d->m_url = tmp;
00435 setModified( false );
00436 return 0;
00437 }
00438
00439 void KEduVocDocument::merge( KEduVocDocument *docToMerge, bool matchIdentifiers )
00440 {
00441 kDebug(1100) << "Merging of docs is not implemented";
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651 }
00652
00653
00654 KEduVocExpression *KEduVocDocument::entry( int index )
00655 {
00656 if ( index < 0 || index >= d->m_vocabulary.size() )
00657 return 0;
00658 else
00659 return &d->m_vocabulary[index];
00660 }
00661
00662
00663 void KEduVocDocument::removeEntry( int index )
00664 {
00665 if ( index >= 0 && index < d->m_vocabulary.size() ) {
00666 d->m_vocabulary.removeAt( index );
00667 }
00668
00669
00670 for (int i = 0; i < d->m_lessons.size(); ++i)
00671 {
00672 d->m_lessons[i].decrementEntriesAbove(index);
00673 }
00674 }
00675
00676
00677 int KEduVocDocument::indexOfIdentifier( const QString& name ) const
00678 {
00679 for ( int i=0; i < d->m_identifiers.count(); i++ ) {
00680 if ( d->m_identifiers.value(i).name() == name ) {
00681 return i;
00682 }
00683 }
00684 return -1;
00685 }
00686
00687
00688 KEduVocIdentifier& KEduVocDocument::identifier( int index )
00689 {
00690 if ( index < 0 || index >= d->m_identifiers.size() ) {
00691 kError() << " Error: Invalid identifier index: " << index;
00692 }
00693 return d->m_identifiers[index];
00694 }
00695
00696
00697 void KEduVocDocument::setIdentifier( int idx, const KEduVocIdentifier &id )
00698 {
00699 if ( idx >= 0 && idx < d->m_identifiers.size() ) {
00700 d->m_identifiers[idx] = id;
00701 }
00702 }
00703
00704
00705 QString KEduVocDocument::tenseName( int index ) const
00706 {
00707 if ( index >= d->m_tenseDescriptions.size() )
00708 return "";
00709 else
00710 return d->m_tenseDescriptions[index];
00711 }
00712
00713
00714 void KEduVocDocument::setTenseName( int idx, QString &id )
00715 {
00716 if ( idx >= d->m_tenseDescriptions.size() )
00717 for ( int i = d->m_tenseDescriptions.size(); i <= idx; i++ )
00718 d->m_tenseDescriptions.append( "" );
00719
00720 d->m_tenseDescriptions[idx] = id;
00721 }
00722
00723
00724 QStringList KEduVocDocument::tenseDescriptions() const
00725 {
00726 return d->m_tenseDescriptions;
00727 }
00728
00729
00730 void KEduVocDocument::setTenseDescriptions( const QStringList &names )
00731 {
00732 d->m_tenseDescriptions = names;
00733 }
00734
00735
00736 int KEduVocDocument::sizeHint( int idx ) const
00737 {
00738 if ( idx < 0 ) {
00739 idx = -idx;
00740 if ( idx >= d->m_extraSizeHints.size() )
00741 return 80;
00742 else {
00743
00744 return d->m_extraSizeHints[idx];
00745 }
00746 } else {
00747 if ( idx >= d->m_sizeHints.size() )
00748 return 150;
00749 else {
00750
00751 return d->m_sizeHints[idx];
00752 }
00753 }
00754 }
00755
00756
00757 void KEduVocDocument::setSizeHint( int idx, const int width )
00758 {
00759
00760 if ( idx < 0 ) {
00761 idx = -idx;
00762 if ( idx >= d->m_extraSizeHints.size() ) {
00763 for ( int i = d->m_extraSizeHints.size(); i <= idx; i++ )
00764 d->m_extraSizeHints.append( 80 );
00765 }
00766 d->m_extraSizeHints[idx] = width;
00767
00768 } else {
00769 if ( idx >= d->m_sizeHints.size() ) {
00770 for ( int i = d->m_sizeHints.size(); i <= idx; i++ )
00771 d->m_sizeHints.append( 150 );
00772 }
00773 d->m_sizeHints[idx] = width;
00774 }
00775 }
00776
00777
00778 void KEduVocDocument::removeIdentifier( int index )
00779 {
00780 if ( index < d->m_identifiers.size() && index >= 0 ) {
00781 d->m_identifiers.removeAt( index );
00782 for ( int i = 0; i < d->m_vocabulary.count(); i++ ) {
00783 d->m_vocabulary[i].removeTranslation( index );
00784 for ( int j = index; j < d->m_identifiers.size(); j++ ) {
00785 d->m_vocabulary[i].translation(j) = d->m_vocabulary[i].translation(j+1);
00786 }
00787 }
00788 }
00789 }
00790
00791
00792 bool KEduVocDocument::isModified() const
00793 {
00794 return d->m_dirty;
00795 }
00796
00797
00798 int KEduVocDocument::entryCount() const
00799 {
00800 return d->m_vocabulary.count();
00801 }
00802
00803
00804 void KEduVocDocument::resetEntry( int index, int lesson )
00805 {
00806 foreach(int entry, this->lesson(lesson).entries()) {
00807 d->m_vocabulary[entry].resetGrades( index );
00808 }
00809 }
00810
00811
00812 int KEduVocDocument::identifierCount() const
00813 {
00814 return d->m_identifiers.count();
00815 }
00816
00817 int KEduVocDocument::appendIdentifier( const KEduVocIdentifier& id )
00818 {
00819 int i = d->m_identifiers.size();
00820
00821 d->m_identifiers.append( id );
00822 if ( id.name().isEmpty() ) {
00823 if ( i == 0 ) {
00824 identifier(i).setName(i18nc("The name of the first language/column of vocabulary, if we have to guess it.", "Original"));
00825 } else {
00826 identifier(i).setName(i18nc( "The name of the second, third ... language/column of vocabulary, if we have to guess it.", "Translation %1", i ) );
00827 }
00828 }
00829
00830 if ( i > 0 ) {
00831 for (int j = 0; j < entryCount(); j++) {
00832 entry(j)->translation(i).setType(entry(j)->translation(0).type());
00833 }
00834 }
00835
00836 return i;
00837 }
00838
00839
00840 int KEduVocDocument::appendLesson( const QString &lessonName, bool inPractice )
00841 {
00842 KEduVocLesson lesson;
00843 lesson.setName( lessonName );
00844 lesson.setInPractice( inPractice );
00845 d->m_lessons.append( lesson );
00846 return d->m_lessons.count() - 1;
00847 }
00848
00849 QList<KEduVocLesson> & KEduVocDocument::lessons() const
00850 {
00851 return d->m_lessons;
00852 }
00853
00854 KEduVocLesson & KEduVocDocument::lesson( int index )
00855 {
00856 return d->m_lessons[index];
00857 }
00858
00859
00860 KUrl KEduVocDocument::url() const
00861 {
00862 return d->m_url;
00863 }
00864
00865
00866 void KEduVocDocument::setUrl( const KUrl& url )
00867 {
00868 d->m_url = url;
00869 }
00870
00871
00872 QString KEduVocDocument::title() const
00873 {
00874 if ( d->m_title.isEmpty() )
00875 return d->m_url.fileName();
00876 else
00877 return d->m_title;
00878 }
00879
00880
00881 QString KEduVocDocument::author() const
00882 {
00883 return d->m_author;
00884 }
00885
00886
00887 QString KEduVocDocument::license() const
00888 {
00889 return d->m_license;
00890 }
00891
00892
00893 QString KEduVocDocument::documentComment() const
00894 {
00895 return d->m_comment;
00896 }
00897
00898 void KEduVocDocument::setCategory( const QString & category )
00899 {
00900 d->m_category = category;
00901 }
00902
00903 QString KEduVocDocument::category() const
00904 {
00905 return d->m_category;
00907 }
00908
00909 void KEduVocDocument::queryIdentifier( QString &org, QString &trans ) const
00910 {
00911 org = d->m_queryorg;
00912 trans = d->m_querytrans;
00913 }
00914
00915
00916 void KEduVocDocument::setQueryIdentifier( const QString &org, const QString &trans )
00917 {
00918 d->m_queryorg = org;
00919 d->m_querytrans = trans;
00920 }
00921
00922
00923 void KEduVocDocument::setTitle( const QString & title )
00924 {
00925 d->m_title = title.simplified();
00926 }
00927
00928
00929 void KEduVocDocument::setAuthor( const QString & s )
00930 {
00931 d->m_author = s.simplified();
00932 }
00933
00934
00935 void KEduVocDocument::setLicense( const QString & s )
00936 {
00937 d->m_license = s.simplified();
00938 }
00939
00940
00941 void KEduVocDocument::setDocumentComment( const QString & s )
00942 {
00943 d->m_comment = s.trimmed();
00944 }
00945
00946
00947 void KEduVocDocument::setGenerator( const QString & generator )
00948 {
00949 d->m_generator = generator;
00950 }
00951
00952
00953 QString KEduVocDocument::generator() const
00954 {
00955 return d->m_generator;
00956 }
00957
00958
00959 QString KEduVocDocument::version() const
00960 {
00961 return d->m_version;
00962 }
00963
00964
00965 void KEduVocDocument::setVersion( const QString & vers )
00966 {
00967 d->m_version = vers;
00968 }
00969
00970
00971 int KEduVocDocument::currentLesson() const
00972 {
00973 return d->m_currentLesson;
00974 }
00975
00976
00977 void KEduVocDocument::setCurrentLesson( int lesson )
00978 {
00979 d->m_currentLesson = lesson;
00980 }
00981
00982
00983 QStringList KEduVocDocument::lessonNames() const
00984 {
00985 QStringList descriptions;
00986 foreach ( KEduVocLesson lesson, d->m_lessons ) {
00987 descriptions.append(lesson.name());
00988 }
00989 return descriptions;
00990 }
00991
00992 int KEduVocDocument::lessonCount() const
00993 {
00994 return d->m_lessons.count();
00995 }
00996
00997 bool KEduVocDocument::removeLesson( int lessonIndex, int deleteMode )
00998 {
00999 if (deleteMode == DeleteEmptyLesson) {
01000 if (d->m_lessons[lessonIndex].entryCount() > 0) {
01001 return false;
01002 }
01003 }
01004 else if (deleteMode == DeleteEntriesAndLesson) {
01005 while (d->m_lessons[lessonIndex].entryCount() > 0) {
01006
01007 int entry = d->m_lessons[lessonIndex].entries()[0];
01008
01009 d->m_lessons[lessonIndex].removeEntry(entry);
01010
01011 removeEntry(entry);
01012 }
01013 }
01014
01015
01016 for ( int ent = 0; ent < entryCount(); ent++ ) {
01017 if ( entry( ent )->lesson() > lessonIndex ) {
01018 entry( ent )->setLesson( entry( ent )->lesson()-1 );
01019 }
01020 }
01021
01022
01023 d->m_lessons.removeAt(lessonIndex);
01024
01025 return true;
01026 }
01027
01028
01029
01030
01031
01032
01033
01034
01035
01037
01038
01039
01040
01041
01042
01043
01044
01045
01046
01047
01048
01049
01050
01051
01052
01053
01054
01055
01056
01057
01058
01059
01060
01061
01062
01063
01064
01065
01066
01067
01068 QString KEduVocDocument::csvDelimiter() const
01069 {
01070 return d->m_csvDelimiter;
01071 }
01072
01073
01074 void KEduVocDocument::setCsvDelimiter( const QString &delimiter )
01075 {
01076 d->m_csvDelimiter = delimiter;
01077 }
01078
01079
01080 class ExpRef
01081 {
01082
01083 public:
01084 ExpRef()
01085 {}
01086 ExpRef( KEduVocExpression *_exp, int _idx )
01087 {
01088 idx = _idx;
01089 exp = _exp;
01090 }
01091
01092 bool operator< ( const ExpRef& y ) const
01093 {
01094 QString s1;
01095 QString s2;
01096 int cmp;
01097 foreach( int i, exp->translationIndices() ) {
01098
01099 s1 = exp->translation( i ).text();
01100 s2 = y.exp->translation( i ).text();
01101 cmp = QString::compare( s1.toUpper(), s2.toUpper() );
01102 if ( cmp != 0 )
01103 return cmp < 0;
01104 }
01105 return cmp < 0;
01106 }
01107
01108 int idx;
01109 KEduVocExpression *exp;
01110 };
01111
01112 typedef QList<ExpRef> ExpRefList;
01113
01114 int KEduVocDocument::cleanUp()
01115 {
01116 int count = 0;
01117 KEduVocExpression *kve1, *kve2;
01118 ExpRefList shadow;
01119 QList<int> to_delete;
01120
01121 for ( int i = 0; i < d->m_vocabulary.count(); i++ ) {
01122 shadow.append( ExpRef( entry( i ), i ) );
01123 }
01124 qStableSort( shadow.begin(), shadow.end() );
01125
01126 int ent_no = 0;
01127 int ent_percent = d->m_vocabulary.size() / 100;
01128 float f_ent_percent = d->m_vocabulary.size() / 100.0;
01129 emit progressChanged( this, 0 );
01130
01131 for ( int i = shadow.size() - 1; i > 0; i-- ) {
01132 kve1 = shadow[i].exp;
01133 kve2 = shadow[i - 1].exp;
01134
01135 ent_no++;
01136 if ( ent_percent != 0 && ( ent_no % ent_percent ) == 0 ) {
01137 emit progressChanged( this, ( int )(( ent_no / f_ent_percent ) / 2.0 ) );
01138 }
01139
01140 bool equal = true;
01141 for ( int l = 0; equal && l < identifierCount(); l++ ) {
01142 if ( kve1->translation( l ).text() != kve2->translation( l ).