00001 #include "Controller.h"
00002
00003 const QString Controller::vocabTreeFilename = QString( "tree" );
00004
00005 Controller::Controller() : vocabTree( NULL ), scheduler( prefs ) {
00006 applicationDirName = QDir::homeDirPath() + QString( "/.toMOTko" );
00007 markedXmlFilename = applicationDirName + QString( "/marked.xml" );
00008 markedFilename = applicationDirName + QString( "/marked.dat.z" );
00009 prefs.setApplicationDirName( applicationDirName );
00010 scheduler.setApplicationDirName( applicationDirName );
00011 }
00012
00013 bool Controller::init() {
00014 QDir applDir( applicationDirName );
00015 if( !applDir.exists() ) {
00016 if( !applDir.mkdir( applicationDirName ) )
00017 return( false );
00018 }
00019 getPreferences().load();
00020 return( true );
00021 }
00022
00023 const QString& Controller::getApplicationDirName() const {
00024 return( applicationDirName );
00025 }
00026
00027 Preferences& Controller::getPreferences() {
00028 return( prefs );
00029 }
00030
00031 Folder* Controller::getVocabTree() {
00032 return( vocabTree );
00033 }
00034
00035 void Controller::startQuiz() {
00036 scheduler.init( getPreferences().getFirstLanguage(), getPreferences().getTestLanguage(), vocabTree );
00037 }
00038
00039 void Controller::restartQuiz() {
00040 scheduler.reinit();
00041 }
00042
00043 bool Controller::isResumableQuizAvailable() {
00044 return( scheduler.isResumableQuizAvailable( BilingualKey( getPreferences().getFirstLanguage(), getPreferences().getTestLanguage() ) ) );
00045 }
00046
00047 bool Controller::resumeQuiz() {
00048 BilingualKey key( getPreferences().getFirstLanguage(), getPreferences().getTestLanguage() );
00049 return( scheduler.load( key ) );
00050 }
00051
00052 void Controller::prepareQuiz() {
00053 emit( progressChanged( getProgress() ) );
00054 }
00055
00056 void Controller::concludeQuiz() {
00057 scheduler.concludeQuiz();
00058 }
00059
00060 Term* Controller::getCurrentTerm() {
00061 TermKey key = scheduler.getCurrentTerm();
00062 Vocabulary* vocab = vocabTree->getVocabulary( key.getVocabId() );
00063 if( vocab && !vocab->isMarkedForDeletion() && vocab->isTermExists( key.getTermId() ) ) {
00064 Term& term = vocab->getTerm( key.getTermId() );
00065 return( &term );
00066 }
00067
00068
00069 scheduler.discardCurrentTerm();
00070 return( getNextTerm() );
00071 }
00072
00073 Term* Controller::getTerm( const TermKey& termKey ) {
00074 Vocabulary* vocab = vocabTree->getVocabulary( termKey.getVocabId() );
00075 if( vocab && !vocab->isMarkedForDeletion() && vocab->isTermExists( termKey.getTermId() ) ) {
00076 Term& term = vocab->getTerm( termKey.getTermId() );
00077 return( &term );
00078 }
00079 return( NULL );
00080 }
00081
00082 Term* Controller::getNextTerm() {
00083 TermKey nextTerm = scheduler.getNextTerm();
00084 if( nextTerm.isNull() )
00085 return( NULL );
00086
00087 TermKey currTerm = scheduler.getCurrentTerm();
00088 Term* term = getTerm( currTerm );
00089 if( term )
00090 return( term );
00091
00092
00093
00094 scheduler.discardCurrentTerm();
00095 return( scheduler.hasNextTerm() ? getNextTerm() : NULL );
00096 }
00097
00098 bool Controller::hasNextTerm() const {
00099 return( scheduler.hasNextTerm() );
00100 }
00101
00102 QString Controller::getQuizFirstLanguage() const {
00103 return( scheduler.getQuizFirstLanguage() );
00104 }
00105
00106 QString Controller::getQuizTestLanguage() const {
00107 return( scheduler.getQuizTestLanguage() );
00108 }
00109
00110 bool Controller::isQuizInProgress() const {
00111 return( scheduler.isQuizInProgress() );
00112 }
00113
00114 int Controller::getProgress() const {
00115 return( scheduler.getProgress() );
00116 }
00117
00118 int Controller::getInitialTermCount() const {
00119 return( scheduler.getInitialTermCount() );
00120 }
00121
00122 Sequence& Controller::getRevealingSequence() {
00123 return( currRevealingSeq );
00124 }
00125
00126 int Controller::getRevealingSequenceStep() const {
00127 return( currRevealingSeqStep );
00128 }
00129
00130 void Controller::incrementRevealingSequenceStep() {
00131 currRevealingSeqStep++;
00132 }
00133
00134 Folder* Controller::addFolder( Folder* parentFolder, Folder* folder = NULL ) {
00135 int newId = parentFolder->getRoot()->getMaxId() + 1;
00136
00137 QString folderLocation = applicationDirName + "/" + parentFolder->getPath() ;
00138 QDir folderDir( folderLocation );
00139 if( !folderDir.exists() ) {
00140 if( !Util::makeDirectory( folderDir.path() ) ) {
00141 cerr << "Cannot create directory " << folderLocation << endl;
00142 return( NULL );
00143 }
00144 }
00145
00146 QString newTitle = ( folder ? folder->getTitle() : QObject::tr( "NewFolder" ) );
00147 Folder* newFolder = new Folder( newId, newTitle );
00148 newFolder->setAuthor( folder ? folder->getAuthor() : parentFolder->getAuthor() );
00149 if( folder ) {
00150 newFolder->setDescription( folder->getDescription() );
00151 newFolder->setCreationDate( folder->getCreationDate() );
00152 newFolder->setModificationDate( folder->getModificationDate() );
00153 }
00154 newFolder->setDirty( true );
00155 if( !saveFolder( newFolder, folderLocation ) ) {
00156 cerr << "Could not save the new folder." << endl;
00157 return( NULL );
00158 }
00159 parentFolder->add( newFolder );
00160 return( newFolder );
00161 }
00162
00163 Vocabulary* Controller::addVocabulary( Folder* parentFolder, Vocabulary* vocab = NULL ) {
00164 int newId = parentFolder->getRoot()->getMaxVocabId() + 1;
00165
00166 QString vocabLocation = applicationDirName + "/" + parentFolder->getPath() + "/v-" + QString::number( newId );
00167 QDir vocabDir( vocabLocation );
00168 if( !vocabDir.exists() ) {
00169 if( !Util::makeDirectory( vocabDir.path() ) ) {
00170 cerr << "Cannot create directory " << vocabLocation << endl;
00171 return( NULL );
00172 }
00173 }
00174
00175 QString newTitle = ( vocab ? vocab->getTitle() : QObject::tr( "NewGlossary" ) );
00176 Vocabulary* newVocab = new Vocabulary( newId, newTitle );
00177 newVocab->setAuthor( vocab ? vocab->getAuthor() : parentFolder->getAuthor() );
00178 if( vocab ) {
00179 newVocab->setDescription( vocab->getDescription() );
00180 newVocab->setCreationDate( vocab->getCreationDate() );
00181 newVocab->setModificationDate( vocab->getModificationDate() );
00182 for( Vocabulary::TermMap::ConstIterator it = vocab->begin(); it != vocab->end(); it++ ) {
00183 const Term& term = *it;
00184 Term newTerm( newVocab->getMaxTermId() + 1, newVocab->getId() );
00185 for( Term::TranslationMap::ConstIterator it2 = term.translationsBegin(); it2 != term.translationsEnd(); it2++ ) {
00186 const Translation& trans = it2.data();
00187 newTerm.addTranslation( trans );
00188 }
00189 for( Term::CommentMap::ConstIterator it3 = term.commentsBegin(); it3 != term.commentsEnd(); it3++ ) {
00190 const BilingualKey& key = it3.key();
00191 const QString& comment = it3.data();
00192 newTerm.addComment( key, comment );
00193 }
00194 if( !term.getImagePath().isNull() ) {
00195
00196
00197 if( term.getImagePath().left( getApplicationDirName().length() ) == getApplicationDirName() ) {
00198 QFileInfo imageToCopyInfo( term.getImagePath() );
00199 QString imageFilename = imageToCopyInfo.fileName();
00200 if( Util::copy( term.getImagePath(), vocabLocation + "/" + imageFilename ) )
00201 newTerm.setImagePath( imageFilename );
00202 else
00203 cerr << "Could not copy " << term.getImagePath() << " to " << ( vocabLocation + "/" + imageFilename ) << endl;
00204 }
00205 else
00206 newTerm.setImagePath( term.getImagePath() );
00207 }
00208 newVocab->addTerm( newTerm );
00209 }
00210 newVocab->setDirty( true );
00211 }
00212 if( !saveVocabulary( newVocab, vocabLocation ) ) {
00213 cerr << "Could not save the new vocabulary." << endl;
00214 return( NULL );
00215 }
00216 parentFolder->add( newVocab );
00217 return( newVocab );
00218 }
00219
00220 void Controller::copy( Vocabulary* vocab ) {
00221 QString firstLang( getPreferences().getFirstLanguage() );
00222 QString testLang( getPreferences().getTestLanguage() );
00223 Vocabulary* vocabCopy = makeCopy( vocab, firstLang, testLang );
00224
00225 QByteArray data;
00226 QDataStream out( data, IO_WriteOnly );
00227 out << *vocabCopy;
00228 setClipboardData( QString( "vocabulary" ), Util::qCompress( data ) );
00229 }
00230
00231 void Controller::copy( Folder* folder ) {
00232 QString firstLang( getPreferences().getFirstLanguage() );
00233 QString testLang( getPreferences().getTestLanguage() );
00234 Folder* folderCopy = makeCopy( folder, firstLang, testLang );
00235
00236 QByteArray data;
00237 QDataStream out( data, IO_WriteOnly );
00238 out << *folderCopy;
00239
00240
00241
00242
00243 QMap<int,Vocabulary> vocabularies;
00244 folderCopy->buildVocabCopiesMap( vocabularies );
00245 out << vocabularies;
00246
00247 setClipboardData( QString( "folder" ), Util::qCompress( data ) );
00248 }
00249
00250 Vocabulary* Controller::makeCopy( Vocabulary* vocab, const QString& firstLang, const QString& testLang ) const {
00251 QStringList languages;
00252 languages << firstLang << testLang;
00253
00254 Vocabulary* vocabCopy = new Vocabulary( vocab->getId(), vocab->getTitle() );
00255 vocabCopy->setDescription( vocab->getDescription() );
00256 vocabCopy->setAuthor( vocab->getAuthor() );
00257 vocabCopy->setCreationDate( vocab->getCreationDate() );
00258 vocabCopy->setModificationDate( vocab->getModificationDate() );
00259 for( Vocabulary::TermMap::ConstIterator it = vocab->begin(); it != vocab->end(); it++ ) {
00260 const Term& term = it.data();
00261 Term* termCopy = new Term( vocabCopy->getMaxTermId() + 1, vocabCopy->getId() );
00262
00263 for( QStringList::ConstIterator it = languages.begin(); it != languages.end(); it++ ) {
00264 const QString& lang = *it;
00265 if( term.isTranslationExists( lang ) ) {
00266 Translation transCopy( term.getTranslation( lang ) );
00267 termCopy->addTranslation( transCopy );
00268 }
00269 }
00270 BilingualKey commentKey( firstLang, testLang );
00271 if( term.isCommentExists( commentKey ) )
00272 termCopy->addComment( commentKey, term.getComment( commentKey ) );
00273
00274 termCopy->setImagePath( getResolvedImagePath( term.getImagePath(), *vocab ) );
00275
00276 vocabCopy->addTerm( *termCopy );
00277 }
00278 return( vocabCopy );
00279 }
00280
00281 Folder* Controller::makeCopy( Folder* folder, const QString& firstLang, const QString& testLang ) const {
00282 QStringList languages;
00283 languages << firstLang << testLang;
00284
00285 Folder* folderCopy = new Folder( folder->getId(), folder->getTitle() );
00286 folderCopy->setDescription( folder->getDescription() );
00287 folderCopy->setAuthor( folder->getAuthor() );
00288 folderCopy->setCreationDate( folder->getCreationDate() );
00289 folderCopy->setModificationDate( folder->getModificationDate() );
00290 for( Base* folderChild = folder->first(); folderChild; folderChild = folder->next() ) {
00291 if( strcmp( folderChild->className(), "Folder" ) == 0 ) {
00292 Folder* childFolder = (Folder*)folderChild;
00293 if( childFolder->containsTermWithTranslations( firstLang, testLang ) ) {
00294 Folder* childFolderCopy = makeCopy( childFolder, firstLang, testLang );
00295 folderCopy->add( childFolderCopy );
00296 }
00297 }
00298 else if( strcmp( folderChild->className(), "Vocabulary" ) == 0 ) {
00299 Vocabulary* childVocab = (Vocabulary*)folderChild;
00300 if( childVocab->containsTermWithTranslations( firstLang, testLang ) ) {
00301 Vocabulary* childVocabCopy = makeCopy( childVocab, firstLang, testLang );
00302 folderCopy->add( childVocabCopy );
00303 }
00304 }
00305 }
00306 return( folderCopy );
00307 }
00308
00309 Vocabulary* Controller::loadVocabulary( const QString& parentDir ) {
00310 Vocabulary* vocab = NULL;
00311 QDir dir( parentDir );
00312 QString vocabDirName = dir.dirName();
00313 int indexOfDash = vocabDirName.find( "-" );
00314 if( indexOfDash > 0 ) {
00315 bool isOk;
00316 QString strVocabId = vocabDirName.right( vocabDirName.length() - indexOfDash - 1 );
00317 int vocabId = strVocabId.toInt( &isOk );
00318 QString filename( parentDir + QString( "/vocab-" ) + QString::number( vocabId ) + QString( ".gz" ) );
00319 QFile compressedBinFile( filename );
00320 if( compressedBinFile.exists() ) {
00321 vocab = new Vocabulary();
00322 if( !vocab->load( filename ) ) {
00323 delete( vocab );
00324 vocab = NULL;
00325 }
00326 }
00327 }
00328 if( vocab == NULL )
00329 cerr << "Could not load vocab file in directory " << parentDir << endl;
00330 return( vocab );
00331 }
00332
00333 bool Controller::loadVocabulariesRec( Folder* folder ) {
00334 for( Base* child = folder->first(); child; child = folder->next() ) {
00335 if( strcmp( child->className(), "Vocabulary" ) == 0 ) {
00336 Vocabulary* vocab = (Vocabulary*)child;
00337 QString filename( applicationDirName + QString( "/" ) + QString::number( vocab->getId() ) + QString( ".dat.z" ) );
00338 QFile compressedBinFile( filename );
00339 if( compressedBinFile.exists() ) {
00340 if( !vocab->load( filename ) )
00341 return( false );
00342 }
00343 }
00344 else if( strcmp( child->className(), "Folder" ) == 0 ) {
00345 if( !loadVocabulariesRec( (Folder*)child ) )
00346 return( false );
00347 }
00348 }
00349 return( true );
00350 }
00351
00352 Base* Controller::importData( Folder* folder, const QString& filename, const QStringList& languages ) {
00353 Folder* rootFolder = folder->getRoot();
00354
00355 int status;
00356 Base* newItem = NULL;
00357
00358 zipFile inputFile = unzOpen( filename.latin1() );
00359 if( inputFile == NULL )
00360 return( NULL );
00361
00362 unz_global_info gi;
00363 status = unzGetGlobalInfo( inputFile, &gi );
00364
00365 if( status == UNZ_OK ) {
00366 QMap<int,Vocabulary*> newVocabs;
00367 QMap<int,Folder*> newFolders;
00368 Folder* newFolder = NULL;
00369 Vocabulary* newVocab = NULL;
00370 int newVocabId = -1;
00371 int newFolderId = -1;
00372
00373
00374 for( uLong i = 0; i < gi.number_entry; i++ ) {
00375 char filename_inzip[ 256 ];
00376 unz_file_info file_info;
00377 status = unzGetCurrentFileInfo( inputFile, &file_info, filename_inzip, sizeof( filename_inzip ), NULL, 0, NULL, 0 );
00378 if( status != UNZ_OK )
00379 break;
00380
00381 QString filenameInZip( filename_inzip );
00382 QFileInfo fileInfo( filenameInZip );
00383
00384
00385 if( fileInfo.extension() == "gif" || fileInfo.extension() == "png" ) {
00386 int importedVocabId = findVocabId( fileInfo.dirPath() );
00387 if( newVocabs.contains( importedVocabId ) )
00388 newVocab = newVocabs[ importedVocabId ];
00389 else{
00390 newVocabId = ( newVocabId == -1 ? rootFolder->getMaxVocabId() + 1 : newVocabId + 1 );
00391 newVocab = new Vocabulary( newVocabId );
00392 newVocabs.insert( importedVocabId, newVocab );
00393 if( !newItem )
00394 newItem = newVocab;
00395 else {
00396 int parentFolderId = findParentFolderId( fileInfo.dirPath() );
00397 if( parentFolderId != -1 && newFolders.contains( parentFolderId ) )
00398 newFolders[ parentFolderId ]->add( newVocab );
00399 }
00400 }
00401
00402 QString imageLocation = applicationDirName + "/" + folder->getPath() + convertPath( fileInfo.dirPath(), newFolders ) +
00403 "/v-" + QString::number( newVocab->getId() ) + "/" + fileInfo.fileName();
00404 importImageFromZip( imageLocation, inputFile );
00405 }
00406 else if( fileInfo.extension() == "xml" ) {
00407 if( fileInfo.fileName().left( 7 ) == "folder-" ) {
00408 int importedFolderId = findFolderId( fileInfo.fileName() );
00409
00410 if( newFolders.contains( importedFolderId ) )
00411 newFolder = newFolders[ importedFolderId ];
00412 else {
00413 newFolderId = ( newFolderId == -1 ? rootFolder->getMaxId() + 1 : newFolderId + 1 );
00414 newFolder = new Folder( newFolderId );
00415 newFolders.insert( importedFolderId, newFolder );
00416 if( !newItem )
00417 newItem = newFolder;
00418 else {
00419 int parentFolderId = findParentFolderId( fileInfo.dirPath() );
00420 if( parentFolderId != -1 && newFolders.contains( parentFolderId ) )
00421 newFolders[ parentFolderId ]->add( newFolder );
00422 }
00423 }
00424
00425 QString folderLocation = applicationDirName + "/" + folder->getPath() + convertPath( fileInfo.dirPath(), newFolders );
00426 importFolderFromZip( newFolder, folderLocation, inputFile );
00427 }
00428 else if( fileInfo.fileName().left( 6 ) == "vocab-" ) {
00429 int importedVocabId = findVocabId( fileInfo.dirPath() );
00430 if( newVocabs.contains( importedVocabId ) )
00431 newVocab = newVocabs[ importedVocabId ];
00432 else {
00433 newVocabId = ( newVocabId == -1 ? rootFolder->getMaxVocabId() + 1 : newVocabId + 1 );
00434 newVocab = new Vocabulary( newVocabId );
00435 newVocabs.insert( importedVocabId, newVocab );
00436 if( !newItem )
00437 newItem = newVocab;
00438 else {
00439 int parentFolderId = findParentFolderId( fileInfo.dirPath() );
00440 if( parentFolderId != -1 && newFolders.contains( parentFolderId ) )
00441 newFolders[ parentFolderId ]->add( newVocab );
00442 }
00443 }
00444
00445 QString vocabLocation = applicationDirName + "/" + folder->getPath() + convertPath( fileInfo.dirPath(), newFolders ) +
00446 "/v-" + QString::number( newVocab->getId() );
00447 importVocabularyFromZip( newVocab, vocabLocation, languages, inputFile );
00448 }
00449 }
00450
00451 status = unzGoToNextFile( inputFile );
00452 if( status == UNZ_END_OF_LIST_OF_FILE ) {
00453 status = UNZ_OK;
00454 break;
00455 }
00456 else if( status != UNZ_OK ) {
00457
00458 break;
00459 }
00460 }
00461 }
00462
00463
00464 if( status != UNZ_OK ) {
00465 if( newItem ) {
00466 delete( newItem );
00467 newItem = NULL;
00468 }
00469 }
00470
00471 if( unzClose( inputFile ) != UNZ_OK )
00472 return( NULL );
00473
00474 return( newItem );
00475 }
00476
00477 QStringList Controller::getTranslationLanguagesFromFile( const QString& filename ) const {
00478 QStringList languages;
00479
00480 zipFile inputFile = unzOpen( filename.latin1() );
00481 if( inputFile ) {
00482 unz_global_info gi;
00483 int status = unzGetGlobalInfo( inputFile, &gi );
00484
00485 if( status == UNZ_OK ) {
00486 for( uLong i = 0; i < gi.number_entry; i++ ) {
00487 char filename_inzip[ 256 ];
00488 unz_file_info file_info;
00489 status = unzGetCurrentFileInfo( inputFile, &file_info, filename_inzip, sizeof( filename_inzip ), NULL, 0, NULL, 0 );
00490 if( status != UNZ_OK )
00491 break;
00492
00493 QString filenameInZip( filename_inzip );
00494 QFileInfo fileInfo( filenameInZip );
00495 if( fileInfo.fileName().left( 6 ) == "vocab-" && fileInfo.extension() == "xml" ) {
00496 QStringList vocabLanguages = getVocabularyTranslationLanguagesFromZip( inputFile );
00497 for( QStringList::Iterator it = vocabLanguages.begin(); it != vocabLanguages.end(); it++ ) {
00498 const QString& lang = *it;
00499 if( !languages.contains( lang ) )
00500 languages.append( lang );
00501 }
00502 }
00503
00504 status = unzGoToNextFile( inputFile );
00505 if( status == UNZ_END_OF_LIST_OF_FILE ) {
00506 status = UNZ_OK;
00507 break;
00508 }
00509 else if( status != UNZ_OK ) {
00510 cerr << "Cannot get next entry in Zip file: " << filename.latin1() << endl;
00511 break;
00512 }
00513 }
00514 }
00515
00516 if( unzClose( inputFile ) != UNZ_OK )
00517 cerr << "Cannot close file: " << filename.latin1() << endl;
00518 }
00519 else
00520 cerr << "Cannot open file: " << filename.latin1() << endl;
00521
00522 return( languages );
00523 }
00524
00525 QStringList Controller::getVocabularyTranslationLanguagesFromZip( zipFile inputFile ) const {
00526 QStringList languages;
00527
00528 int status = unzOpenCurrentFile( inputFile );
00529 if( status == UNZ_OK ) {
00530 bool isOk = true;
00531
00532 char* buf = NULL;
00533 uInt size_buf = 8192;
00534 buf = (char*)malloc( size_buf );
00535 if( buf == NULL ) {
00536 cerr << "Cannot allocate memory for unzip buffer." << endl;
00537 status = UNZ_INTERNALERROR;
00538 }
00539
00540 if( status == UNZ_OK ) {
00541 QByteArray ba;
00542 QTextStream ts( ba, IO_WriteOnly );
00543
00544 int totalByteCount = 0;
00545 int readStatus;
00546 for( ;; ) {
00547 readStatus = unzReadCurrentFile( inputFile, buf, size_buf );
00548 if( readStatus > 0 ) {
00549 ts.writeRawBytes( buf, readStatus );
00550 totalByteCount += readStatus;
00551 }
00552 else
00553 break;
00554 }
00555
00556 if( readStatus == 0 ) {
00557 Vocabulary* vocab = new Vocabulary();
00558 QTextStream ts2( ba, IO_ReadOnly );
00559 VocabParser parser( *vocab, languages );
00560 QXmlInputSource source( ts2 );
00561
00562 QXmlSimpleReader reader;
00563 reader.setContentHandler( &parser );
00564 isOk = reader.parse( source );
00565
00566 languages = vocab->getTranslationLanguages();
00567
00568 delete( vocab );
00569 vocab = NULL;
00570 }
00571 }
00572
00573 free( buf );
00574
00575 if( unzCloseCurrentFile( inputFile ) != UNZ_OK )
00576 cerr << "Cannot close zip entry." << endl;
00577 }
00578 else
00579 cerr << "Cannot open zip entry." << endl;
00580
00581 return( languages );
00582 }
00583
00584 bool Controller::importFolderFromZip( Folder* folder, const QString& folderLocation, zipFile inputFile ) {
00585 int status = unzOpenCurrentFile( inputFile );
00586 if( status != UNZ_OK )
00587 return( false );
00588
00589 bool isOk = true;
00590
00591 char* buf = NULL;
00592 uInt size_buf = 8192;
00593 buf = (char*)malloc( size_buf );
00594 if( buf == NULL ) {
00595 cerr << "Cannot allocate memory for unzip buffer." << endl;
00596 status = UNZ_INTERNALERROR;
00597 }
00598
00599 if( status == UNZ_OK ) {
00600 QByteArray ba;
00601 QTextStream ts( ba, IO_WriteOnly );
00602
00603 int totalByteCount = 0;
00604 int readStatus;
00605 for( ;; ) {
00606 readStatus = unzReadCurrentFile( inputFile, buf, size_buf );
00607 if( readStatus > 0 ) {
00608 ts.writeRawBytes( buf, readStatus );
00609 totalByteCount += readStatus;
00610 }
00611 else
00612 break;
00613 }
00614
00615 if( readStatus == 0 ) {
00616 QTextStream ts2( ba, IO_ReadOnly );
00617 FolderParser parser( *folder, folderLocation );
00618 QXmlInputSource source( ts2 );
00619
00620 QXmlSimpleReader reader;
00621 reader.setContentHandler( &parser );
00622 isOk = reader.parse( source );
00623
00624 if( isOk ) {
00625
00626 isOk = Util::makeDirectory( folderLocation );
00627 if( isOk ) {
00628 const QString& folderDataFilename( folderLocation + "/folder-" + QString::number( folder->getId() ) + ".gz" );
00629 isOk = folder->saveMetadata( folderDataFilename );
00630 if( isOk )
00631 folder->setDirty( false );
00632 }
00633 else {
00634 cerr << "Could not create directory " << folderLocation << endl;
00635 isOk = false;
00636 }
00637 }
00638
00639
00640
00641
00642
00643 }
00644 }
00645
00646 free( buf );
00647
00648 unzCloseCurrentFile( inputFile );
00649
00650
00651 return( isOk );
00652 }
00653
00654 bool Controller::importVocabularyFromZip( Vocabulary* vocab, const QString& vocabLocation, const QStringList& languages, zipFile inputFile ) {
00655 int status = unzOpenCurrentFile( inputFile );
00656 if( status != UNZ_OK )
00657 return( false );
00658
00659 bool isOk = true;
00660
00661 char* buf = NULL;
00662 uInt size_buf = 8192;
00663 buf = (char*)malloc( size_buf );
00664 if( buf == NULL ) {
00665 cerr << "Cannot allocate memory for unzip buffer." << endl;
00666 status = UNZ_INTERNALERROR;
00667 }
00668
00669 if( status == UNZ_OK ) {
00670 QByteArray ba;
00671 QTextStream ts( ba, IO_WriteOnly );
00672
00673 int totalByteCount = 0;
00674 int readStatus;
00675 for( ;; ) {
00676 readStatus = unzReadCurrentFile( inputFile, buf, size_buf );
00677 if( readStatus > 0 ) {
00678 ts.writeRawBytes( buf, readStatus );
00679 totalByteCount += readStatus;
00680 }
00681 else
00682 break;
00683 }
00684
00685 if( readStatus == 0 ) {
00686 QTextStream ts2( ba, IO_ReadOnly );
00687 VocabParser parser( *vocab, languages );
00688 QXmlInputSource source( ts2 );
00689
00690 QXmlSimpleReader reader;
00691 reader.setContentHandler( &parser );
00692 isOk = reader.parse( source );
00693 if( isOk ) {
00694 vocab->setDirty( true );
00695 isOk = saveVocabulary( vocab, vocabLocation );
00696 }
00697 }
00698 }
00699
00700 free( buf );
00701
00702 unzCloseCurrentFile( inputFile );
00703
00704
00705 return( isOk );
00706 }
00707
00708 bool Controller::importImageFromZip( const QString& imagePath, zipFile inputFile ) {
00709 int status = unzOpenCurrentFile( inputFile );
00710 if( status != UNZ_OK )
00711 return( false );
00712
00713 bool isOk = true;
00714
00715 char* buf = NULL;
00716 uInt size_buf = 8192;
00717 buf = (char*)malloc( size_buf );
00718 if( buf == NULL ) {
00719 cerr << "Cannot allocate memory for unzip buffer." << endl;
00720 status = UNZ_INTERNALERROR;
00721 }
00722
00723 if( status == UNZ_OK ) {
00724 QFile imageFile( imagePath );
00725
00726 const QString imageDir = QFileInfo( imageFile ).dirPath( true );
00727 isOk = Util::makeDirectory( imageDir );
00728 if( isOk ) {
00729 isOk = imageFile.open( IO_WriteOnly );
00730 if( isOk ) {
00731 QTextStream ts( &imageFile );
00732
00733 int totalByteCount = 0;
00734 int readStatus;
00735 for( ;; ) {
00736 readStatus = unzReadCurrentFile( inputFile, buf, size_buf );
00737 if( readStatus > 0 ) {
00738 ts.writeRawBytes( buf, readStatus );
00739 totalByteCount += readStatus;
00740 }
00741 else
00742 break;
00743 }
00744 imageFile.close();
00745 }
00746 else
00747 cerr << "Could not create file " << imagePath << endl;
00748 }
00749 else
00750 cerr << "Could not create directory " << imageDir << endl;
00751 }
00752
00753 free( buf );
00754
00755 unzCloseCurrentFile( inputFile );
00756
00757
00758 return( isOk );
00759 }
00760
00761 void Controller::loadData() {
00762 vocabTree = loadFolder( applicationDirName );
00763
00764 if( !vocabTree ) {
00765 Folder* folder = new Folder( 1, QObject::tr( "MyGlossaries" ) );
00766 folder->setMarkedForStudy( true );
00767 folder->setDirty( true );
00768 vocabTree = folder;
00769 }
00770 loadMarkedItems( vocabTree );
00771 }
00772
00773 void Controller::rightAnswer() {
00774 scheduler.rightAnswer();
00775 emit( progressChanged( getProgress() ) );
00776 }
00777
00778 void Controller::wrongAnswer() {
00779 scheduler.wrongAnswer();
00780 emit( progressChanged( getProgress() ) );
00781 }
00782
00783 void Controller::reveal() {
00784 }
00785
00786 Folder* Controller::loadFolder( const QString& parentDir ) {
00787 Folder* newFolder = NULL;
00788
00789 QDir dir( parentDir );
00790 bool isOk;
00791 dir.dirName().toInt( &isOk );
00792
00793 if( isOk ) {
00794 newFolder = new Folder();
00795 QString folderMetadataFile = QString( parentDir + "/folder-" + dir.dirName() + ".gz" );
00796 if( !newFolder->loadMetadata( folderMetadataFile ) ) {
00797 cerr << "Could not load metadata file " << folderMetadataFile << endl;
00798 delete( newFolder );
00799 return( NULL );
00800 }
00801 }
00802
00803 QStringList entries = dir.entryList();
00804 for( QStringList::Iterator it = entries.begin(); it != entries.end(); it++ ) {
00805 QString entry = *it;
00806 QString entryPath = parentDir + "/" + entry;
00807 QFileInfo info( entryPath );
00808 if( info.isDir() && entry != "." && entry != ".." ) {
00809 if( !isOk )
00810 newFolder = loadFolder( entryPath );
00811 else {
00812 if( entry.left( 2 ) == QString( "v-" ) ) {
00813 Vocabulary* childVocab = loadVocabulary( entryPath );
00814 if( childVocab )
00815 newFolder->add( childVocab );
00816 }
00817 else {
00818 Folder* childFolder = loadFolder( entryPath );
00819 if( childFolder )
00820 newFolder->add( childFolder );
00821 }
00822 }
00823 }
00824 }
00825
00826 return( newFolder );
00827 }
00828
00829 bool Controller::saveFolder( Folder* folder, const QString& parentDir ) const {
00830
00831
00832 QString folderPath( parentDir + QString( "/" ) + QString::number( folder->getId() ) );
00833 QDir folderDir( folderPath );
00834 if( folder->isDirty() && !folderDir.exists() ) {
00835 if( !folderDir.mkdir( folderDir.path() ) ) {
00836 cerr << "Could not make directory " << folderPath << endl;
00837 return( false );
00838 }
00839 }
00840
00841
00842 if( folder->isDirty() ) {
00843 QString folderDataFilename( QString( folderDir.path() + QString( "/folder-" ) + QString::number( folder->getId() ) + QString( ".gz" ) ) );
00844 if( !folder->saveMetadata( folderDataFilename ) ) {
00845 cerr << "Could not write folder metadata " << folderDataFilename << endl;
00846 return( false );
00847 }
00848 folder->setDirty( false );
00849 }
00850
00851
00852 if( !folder->isEmpty() ) {
00853 for( Base* folderChild = folder->first(); folderChild; folderChild = folder->next() ) {
00854 if( strcmp( folderChild->className(), "Folder" ) == 0 ) {
00855 Folder* childFolder = (Folder*)folderChild;
00856 if( !childFolder->isMarkedForDeletion() )
00857 saveFolder( childFolder, folderDir.path() );
00858 }
00859 else if( strcmp( folderChild->className(), "Vocabulary" ) == 0 ) {
00860 Vocabulary* childVocab = (Vocabulary*)folderChild;
00861 if( !childVocab->isMarkedForDeletion() )
00862 saveVocabulary( childVocab, folderDir.path() );
00863 }
00864 }
00865 }
00866
00867 return( true );
00868 }
00869
00870 void Controller::writeVocabulariesInXml( Folder* folder, int depth, QTextStream& ts, QStringList* languages ) {
00871 if( !folder->isEmpty() ) {
00872 for( Base* folderChild = folder->first(); folderChild; folderChild = folder->next() ) {
00873 if( strcmp( folderChild->className(), "Folder" ) == 0 )
00874 writeVocabulariesInXml( (Folder*)folderChild, depth, ts, languages );
00875 else if( strcmp( folderChild->className(), "Vocabulary" ) == 0 ) {
00876 Vocabulary* vocab = (Vocabulary*)folderChild;
00877 writeVocabularyInXml( ts, *vocab, languages, false, depth );
00878 }
00879 }
00880 }
00881 }
00882
00883 bool Controller::deleteItemsMarkedForDeletion( Folder* folder ) {
00884 for( Base* childItem = folder->first(); childItem; childItem = folder->next() ) {
00885 if( strcmp( childItem->className(), "Folder" ) == 0 ) {
00886 Folder* childFolder = new Folder( *((Folder*)childItem) );
00887 deleteItemsMarkedForDeletion( childFolder );
00888 }
00889 else if( strcmp( childItem->className(), "Vocabulary" ) == 0 ) {
00890 Vocabulary* childVocab = new Vocabulary( *((Vocabulary*)childItem) );
00891 if( childVocab->isMarkedForDeletion() ) {
00892 QString vocabDir( applicationDirName + "/" + folder->getPath() + "/v-" + QString::number( childVocab->getId() ) );
00893 if( !Util::deleteDirectory( vocabDir ) ) {
00894 cerr << "Cannot delete glossary directory " << vocabDir << endl;
00895 return( false );
00896 }
00897 }
00898 }
00899 }
00900
00901 if( folder->isMarkedForDeletion() ) {
00902
00903 getPreferences().setFolderOpen( folder->getId(), true );
00904 QString folderDir( applicationDirName + "/" + folder->getPath() );
00905 if( !Util::deleteDirectory( folderDir ) ) {
00906 cerr << "Cannot delete folder directory " << folderDir << endl;
00907 return( false );
00908 }
00909 }
00910
00911 return( true );
00912 }
00913
00914 int Controller::findFolderId( const QString& filename ) const {
00915 int indexOfDash = filename.find( "-" );
00916 int indexOfDot = filename.find( "." );
00917 const QString& strFolderId = filename.mid( indexOfDash + 1, indexOfDot - indexOfDash - 1 );
00918 bool isOk;
00919 int folderId = strFolderId.toInt( &isOk );
00920 return( isOk ? folderId : -1 );
00921 }
00922
00923 int Controller::findParentFolderId( const QString& dirPath ) const {
00924 int lastSlashPos = dirPath.findRev( "/" );
00925 if( lastSlashPos > 0 ) {
00926 int beforeLastSlashPos = dirPath.findRev( "/", lastSlashPos - 1 );
00927 if( beforeLastSlashPos > 0 ) {
00928 QString strParentFolderId = dirPath.mid( beforeLastSlashPos + 1, lastSlashPos - beforeLastSlashPos - 1 );
00929 bool isOk;
00930 int parentFolderId = strParentFolderId.toInt( &isOk );
00931 return( isOk ? parentFolderId : -1 );
00932 }
00933 else {
00934 QString strParentFolderId = dirPath.left( lastSlashPos );
00935 bool isOk;
00936 int parentFolderId = strParentFolderId.toInt( &isOk );
00937 return( isOk ? parentFolderId : -1 );
00938 }
00939 }
00940 return( -1 );
00941 }
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952 int Controller::findVocabId( const QString& dirPath ) const {
00953 int posOfLeftDelim = dirPath.find( "v-" );
00954 int posOfRightDelim = dirPath.findRev( "/" );
00955 QString strImportedVocabId = dirPath.mid( posOfLeftDelim + 1, posOfRightDelim - posOfLeftDelim - 1 );
00956 bool isOk;
00957 int importedVocabId = strImportedVocabId.toInt( &isOk );
00958 return( isOk ? importedVocabId : -1 );
00959 }
00960
00961 QString Controller::convertPath( const QString& path, QMap<int,Folder*>& newFolders ) const {
00962 QString realPath;
00963 QStringList subDirs = QStringList::split( "/", path );
00964 for( QStringList::Iterator it = subDirs.begin(); it != subDirs.end(); it++ ) {
00965 const QString& strFolderId = (*it);
00966 bool isOk;
00967 int subDirFolderId = strFolderId.toInt( &isOk );
00968 if( isOk && newFolders.contains( subDirFolderId ) ) {
00969 Folder* assocFolder = newFolders[ subDirFolderId ];
00970 realPath += "/" + QString::number( assocFolder->getId() );
00971 }
00972 }
00973 return( realPath );
00974 }
00975
00976 bool Controller::saveData() {
00977 if( !deleteObsoleteData() ) {
00978
00979
00980 cerr << "Could not delete obsolete data files." << endl;
00981 }
00982 if( !deleteItemsMarkedForDeletion( vocabTree ) ) {
00983
00984
00985 cerr << "Could not delete all items marked for deletion." << endl;
00986 }
00987 if( !saveFolder( vocabTree, applicationDirName ) )
00988 return( false );
00989 if( !saveMarkedItems( vocabTree ) )
00990 return( false );
00991 return( prefs.save() );
00992 }
00993
00994 bool Controller::saveMarkedItems( Folder* folder ) {
00995 QByteArray data;
00996
00997 QDataStream out( data, IO_WriteOnly );
00998 out.setVersion( 3 );
00999
01000
01001 out << Q_UINT32( Preferences::magicNumber ) << Q_UINT16( 0x0011 );
01002
01003 IdList folderIds;
01004 IdList vocabIds;
01005 IdListMap termIds;
01006
01007 saveMarkedItemsRec( folder, folderIds, vocabIds, termIds );
01008
01009 out << folderIds << vocabIds << termIds;
01010
01011 QByteArray compressedData( Util::qCompress( data ) );
01012
01013 QFile dataFile( markedFilename );
01014 QFileInfo dataFileInfo( dataFile );
01015
01016 if( !Util::makeDirectory( dataFileInfo.dirPath() ) )
01017 return( false );
01018
01019 if( !dataFile.open( IO_WriteOnly ) )
01020 return( false );
01021
01022 int ret = dataFile.writeBlock( compressedData );
01023 dataFile.close();
01024
01025 if( ret == -1 || dataFile.status() != IO_Ok ) {
01026 dataFile.resetStatus();
01027 return( false );
01028 }
01029
01030 return( true );
01031 }
01032
01033 void Controller::saveMarkedItemsRec( Folder* folder, IdList& folderIds, IdList& vocabIds, IdListMap& termIds ) {
01034 if( folder->isMarkedForStudy() )
01035 folderIds.append( folder->getId() );
01036 if( !folder->isEmpty() ) {
01037 for( Base* folderChild = folder->first(); folderChild; folderChild = folder->next() ) {
01038 if( strcmp( folderChild->className(), "Folder" ) == 0 )
01039 saveMarkedItemsRec( (Folder*)folderChild, folderIds, vocabIds, termIds );
01040 else if( strcmp( folderChild->className(), "Vocabulary" ) == 0 )
01041 saveMarkedItemsRec( (Vocabulary*)folderChild, vocabIds, termIds );
01042 }
01043 }
01044 }
01045
01046 void Controller::saveMarkedItemsRec( Vocabulary* vocab, IdList& vocabIds, IdListMap& termIds ) {
01047 if( vocab->isMarkedForStudy() )
01048 vocabIds.append( vocab->getId() );
01049 IdList termIdList;
01050 for( Vocabulary::TermMap::ConstIterator it = vocab->begin(); it != vocab->end(); it++ ) {
01051 const Term& term = it.data();
01052 if( term.isMarkedForStudy() )
01053 termIdList.append( term.getId() );
01054 }
01055 termIds.insert( vocab->getId(), termIdList );
01056 }
01057
01058 void Controller::loadMarkedItems( Folder* folder ) {
01059 QFile markedFile( markedFilename );
01060 if( markedFile.exists() ) {
01061 if( !markedFile.open( IO_ReadOnly ) )
01062 return;
01063
01064 QByteArray compressedData( markedFile.readAll() );
01065 QByteArray data( Util::qUncompress( compressedData ) );
01066
01067 QDataStream in( data, IO_ReadOnly );
01068
01069 Q_UINT32 tempMagicNumber;
01070 Q_UINT16 tempVersion;
01071
01072 IdList tempFolderIds;
01073 IdList tempVocabIds;
01074 IdListMap tempTermIds;
01075
01076 in >> tempMagicNumber >> tempVersion;
01077
01078 if( tempMagicNumber != Preferences::magicNumber )
01079 cerr << "Wrong magic number: Incompatible data file for marked file." << endl;
01080 if( tempVersion > 0x0011 )
01081 cerr << "Marked data file is from a more recent version. Upgrade toMOTko." << endl;
01082
01083 in.setVersion( 3 );
01084 in >> tempFolderIds >> tempVocabIds >> tempTermIds;
01085
01086 markedFile.close();
01087
01088 initMarkedForStudyRec( folder, tempFolderIds, tempVocabIds, tempTermIds );
01089 }
01090 else {
01091 QFile markedXmlFile( markedXmlFilename );
01092 if( markedXmlFile.exists() ) {
01093 MarkedItemsParser parser;
01094 QXmlInputSource source( markedXmlFile );
01095 QXmlSimpleReader reader;
01096 reader.setContentHandler( &parser );
01097 reader.parse( source );
01098 initMarkedForStudyRec( folder, *(parser.getMarkedFolders()), *(parser.getMarkedVocabs()), *(parser.getMarkedTerms()) );
01099 }
01100
01101 }
01102 }
01103
01104 void Controller::initMarkedForStudyRec( Folder* folder, IdList& folderIds, IdList& vocabIds, IdListMap& termIds ) {
01105 if( folderIds.contains( folder->getId() ) )
01106 folder->setMarkedForStudy( true );
01107 if( !folder->isEmpty() ) {
01108 for( Base* folderChild = folder->first(); folderChild; folderChild = folder->next() ) {
01109 if( strcmp( folderChild->className(), "Folder" ) == 0 )
01110 initMarkedForStudyRec( (Folder*)folderChild, folderIds, vocabIds, termIds );
01111 else if( strcmp( folderChild->className(), "Vocabulary" ) == 0 )
01112 initMarkedForStudyRec( (Vocabulary*)folderChild, vocabIds, termIds );
01113 }
01114 }
01115 }
01116
01117 void Controller::initMarkedForStudyRec( Vocabulary* vocab, IdList& vocabIds, IdListMap& termIds ) {
01118 if( vocabIds.contains( vocab->getId() ) )
01119 vocab->setMarkedForStudy( true );
01120 IdList termIdList = termIds[ vocab->getId() ];
01121 for( IdList::ConstIterator it = termIdList.begin(); it != termIdList.end(); it++ ) {
01122 int termId = *it;
01123 if( vocab->isTermExists( termId ) ) {
01124 Term& term = vocab->getTerm( termId );
01125 term.setMarkedForStudy( true );
01126 }
01127 }
01128 }
01129
01130 bool Controller::exportData( Vocabulary* vocab, const QString& file, QStringList* languages ) const {
01131 zipFile outputFile = zipOpen( file.latin1(), APPEND_STATUS_CREATE );
01132 if( outputFile == NULL )
01133 return( false );
01134
01135 bool isOk = exportVocabularyIntoZip( vocab, outputFile, QString::null, languages );
01136
01137 if( zipClose( outputFile, "Closing comment" ) != 0 )
01138 return( false );
01139
01140 return( isOk );
01141 }
01142
01143 bool Controller::exportVocabularyIntoZip( Vocabulary* vocab, zipFile outputFile, QString path, QStringList* languages ) const {
01144 QString vocabPath = ( path == QString::null ? QString( "v-" + QString::number( vocab->getId() ) ) :
01145 path + "/v-" + QString::number( vocab->getId() ) );
01146
01147
01148 for( Vocabulary::TermMap::ConstIterator it = vocab->begin(); it != vocab->end(); it++ ) {
01149 const Term& term = it.data();
01150 if( term.getImagePath() != QString::null ) {
01151 QString fileExtension = term.getImagePath().right( 4 );
01152 QCString imageDataFilename = QString( vocabPath + "/" + QString::number( term.getId() ) + fileExtension ).latin1();
01153 const char* filenameInZip = (const char*)imageDataFilename.data();
01154 QString absPath = getResolvedImagePath( term.getImagePath(), *vocab );
01155 QFile imageFile( absPath );
01156 if( imageFile.exists() ) {
01157 if( !imageFile.open( IO_ReadOnly ) )
01158 return( false );
01159 QByteArray buffer = imageFile.readAll();
01160 imageFile.close();
01161
01162 int err = writeFileIntoZipFile( outputFile, filenameInZip, buffer.data(), buffer.size() );
01163 if( err != ZIP_OK )
01164 return( false );
01165 }
01166 else {
01167 cerr << "Image " << imageFile.name() << " referenced by glossary " << vocab->getTitle() <<
01168 " was not found, and therefore, was discarded during export." << endl;
01169 }
01170 }
01171 }
01172
01173
01174 QCString dataFilename = QString( vocabPath + "/vocab-" + QString::number( vocab->getId() ) + ".xml" ).latin1();
01175 const char* filenameInZip = (const char*)dataFilename.data();
01176
01177 QByteArray buffer;
01178 QTextStream ts( buffer, IO_WriteOnly );
01179 ts.setEncoding( QTextStream::UnicodeUTF8 );
01180 writeVocabularyInXml( ts, *vocab, languages );
01181 int err = writeFileIntoZipFile( outputFile, filenameInZip, buffer.data(), buffer.size() );
01182
01183 return( err == ZIP_OK );
01184 }
01185
01186 bool Controller::exportData( Folder* folder, const QString& file, QStringList* languages ) const {
01187 zipFile outputFile = zipOpen( file.latin1(), APPEND_STATUS_CREATE );
01188 if( outputFile == NULL )
01189 return( false );
01190
01191 bool isOk = exportFolderRecIntoZip( folder, outputFile, QString::null, languages );
01192
01193 if( zipClose( outputFile, "Closing comment" ) != 0 )
01194 return( false );
01195
01196 return( isOk );
01197 }
01198
01199 bool Controller::exportFolderRecIntoZip( Folder* folder, zipFile outputFile, QString path, QStringList* languages ) const {
01200 QString folderPath = ( path == QString::null ? QString::number( folder->getId() ) :
01201 path + QString( "/" ) + QString::number( folder->getId() ) );
01202 if( !folder->isEmpty() ) {
01203 QCString folderDataFilename = QString( folderPath + "/folder-" + QString::number( folder->getId() ) + ".xml" ).latin1();
01204 const char* filenameInZip = (const char*) ( folderDataFilename.data() );
01205
01206 QByteArray buffer;
01207 QTextStream ts( buffer, IO_WriteOnly );
01208 ts.setEncoding( QTextStream::UnicodeUTF8 );
01209 writeFolderDataInXml( ts, *folder );
01210
01211 int err = writeFileIntoZipFile( outputFile, filenameInZip, buffer.data(), buffer.size() );
01212 if( err != ZIP_OK )
01213 return( false );
01214 }
01215
01216 for( Base* child = folder->first(); child; child = folder->next() ) {
01217 if( strcmp( child->className(), "Vocabulary" ) == 0 ) {
01218 Vocabulary* childVocab = (Vocabulary*)child;
01219 if( !exportVocabularyIntoZip( childVocab, outputFile, folderPath, languages ) )
01220 return( false );
01221 }
01222 else if( strcmp( child->className(), "Folder" ) == 0 ) {
01223 Folder* childFolder = (Folder*)child;
01224 if( !exportFolderRecIntoZip( childFolder, outputFile, folderPath, languages ) )
01225 return( false );
01226 }
01227 }
01228
01229 return( true );
01230 }
01231
01232 int Controller::writeFileIntoZipFile( zipFile outputFile, const char* filename, const char* data, int length ) const {
01233 zip_fileinfo zipFileInfo;
01234
01235 zipFileInfo.tmz_date.tm_sec = zipFileInfo.tmz_date.tm_min = zipFileInfo.tmz_date.tm_hour =
01236 zipFileInfo.tmz_date.tm_mday = zipFileInfo.tmz_date.tm_mon = zipFileInfo.tmz_date.tm_year = 0;
01237 zipFileInfo.dosDate = 0;
01238 zipFileInfo.internal_fa = 0;
01239 zipFileInfo.external_fa = 0;
01240
01241
01242 int err = zipOpenNewFileInZip3( outputFile, filename, &zipFileInfo,
01243 NULL, 0, NULL, 0, NULL ,
01244 Z_DEFLATED ,
01245 5 , 0,
01246
01247 -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
01248 NULL, 0 );
01249 if( err )
01250 return( err );
01251
01252 int writeErr = zipWriteInFileInZip( outputFile, data, length );
01253
01254 err = zipCloseFileInZip( outputFile );
01255
01256 if( writeErr || err )
01257 return( writeErr ? writeErr : err );
01258
01259 return( ZIP_OK );
01260 }
01261
01262 void Controller::writeFolderDataInXml( QTextStream& ts, const Folder& folder ) const {
01263 ts << QString( "<?xml version=\"1.0\"?>" ) << endl;
01264 ts << QString( "<folder id=\"" ) << folder.getId() << QString( "\" name=\"" ) << Util::escapeXml( folder.getTitle() ) << QString( "\"" );
01265
01266 if( !folder.getAuthor().isNull() )
01267 ts << QString( " author=\"" ) << Util::escapeXml( folder.getAuthor() ) << QString( "\"" );
01268 ts << QString( ">" ) << endl;
01269
01270 if( !folder.getDescription().isNull() )
01271 ts << QString( "\t<desc>" ) << Util::escapeXml( folder.getDescription() ) << QString( "</desc>" ) << endl;
01272 ts << QString( "</folder>" ) << endl;
01273 }
01274
01275 void Controller::writeVocabularyInXml( QTextStream& ts, const Vocabulary& vocab, QStringList* languages, bool writeXmlDirective = true, int depth = 0 ) const {
01276 if( writeXmlDirective ) {
01277 for( int i = 0; i < depth; i++ )
01278 ts << "\t";
01279 ts << QString( "<?xml version=\"1.0\"?>" ) << endl;
01280 }
01281
01282 for( int i = 0; i < depth; i++ )
01283 ts << "\t";
01284 ts << QString( "<glossary id=\"" ) << vocab.getId() << "\" name=\"" << Util::escapeXml( vocab.getTitle() ) << "\" ";
01285 ts << QString( "author=\"" ) << Util::escapeXml( vocab.getAuthor() ) << "\">" << endl;
01286
01287 for( int i = 0; i < depth; i++ )
01288 ts << "\t";
01289 ts << QString( "\t<desc>" ) << Util::escapeXml( vocab.getDescription() ) << QString( "</desc>" ) << endl;
01290 for( Vocabulary::TermMap::ConstIterator it = vocab.begin(); it != vocab.end(); it++ ) {
01291 const Term& term = it.data();
01292 for( int i = 0; i < depth; i++ )
01293 ts << "\t";
01294 ts << Util::term2Xml( term, languages, depth + 1 );
01295 }
01296 for( int i = 0; i < depth; i++ )
01297 ts << "\t";
01298 ts << QString( "</glossary>" ) << endl;
01299 }
01300
01301 bool Controller::saveVocabulary( Vocabulary* vocab, const QString& location ) const {
01302
01303
01304 QString folderPath( location.find( "v-" ) == -1 ? location + QString( "/v-" ) + QString::number( vocab->getId() ) : location );
01305 QDir folderDir( folderPath );
01306 if( vocab->isDirty() && !folderDir.exists() ) {
01307 if( !folderDir.mkdir( folderDir.path() ) ) {
01308 cerr << "Cannot create directory " << folderPath << endl;
01309 return( false );
01310 }
01311 }
01312
01313
01314 if( vocab->isDirty() ) {
01315 QString dataFilename( QString( folderDir.path() + QString( "/" ) + QString( "vocab-" ) + QString::number( vocab->getId() ) + QString( ".gz" ) ) );
01316 if( !vocab->save( dataFilename ) ) {
01317 cerr << "Could not write vocab data " << dataFilename << endl;
01318 return( false );
01319 }
01320 vocab->setDirty( false );
01321 }
01322
01323 return( true );
01324 }
01325
01326 void Controller::initRevealingSequence() {
01327 int index = ( rand() % prefs.getActiveRevealingSequenceCount() );
01328 int sequenceCount = prefs.getRevealingSequenceCount();
01329 for( int i = 0, j = 0; i < sequenceCount; i++ ) {
01330 Sequence seq = prefs.getRevealingSequenceAt( i );
01331 if( seq.isEnabled() ) {
01332 if( j == index ) {
01333 currRevealingSeq = seq;
01334 break;
01335 }
01336 else
01337 j++;
01338 }
01339 }
01340 currRevealingSeqStep = 0;
01341 }
01342
01343 void Controller::setClipboardData( const QString& type, const QByteArray& data ) {
01344 clipboardDataType = type;
01345 clipboard = data;
01346 }
01347
01348 QByteArray Controller::getClipboardData() const {
01349 return( clipboard );
01350 }
01351
01352 QString Controller::getClipboardDataType() const {
01353 return( clipboardDataType );
01354 }
01355
01356 bool Controller::isImagePathValid( const QString& path, const Vocabulary& vocab ) const {
01357 if( !path.isNull() ) {
01358 QString absPath = getResolvedImagePath( path, vocab );
01359 QFileInfo info( absPath );
01360 if( info.exists() ) {
01361 QString format = QPixmap::imageFormat( absPath );
01362 if( format == "GIF" || format == "PNG" )
01363 return( true );
01364 }
01365 }
01366 return( false );
01367 }
01368
01369 QString Controller::getResolvedImagePath( const QString& path, const Vocabulary& vocab ) const {
01370 if( path.isNull() )
01371 return( QString::null );
01372 else if( path.left( 1 ) == "/" )
01373 return( path );
01374 else {
01375 QString absPath = getApplicationDirName() + "/" + vocab.getParent()->getPath() + "/v-" + QString::number( vocab.getId() ) + "/" + path;
01376 return( absPath );
01377 }
01378 }
01379
01380 void Controller::clearSearch() {
01381 searchQuery = QString::null;
01382 searchResults.clear();
01383 }
01384
01385 QValueList<TermKey> Controller::search( const QString& query, const QString& firstLang = QString::null, const QString& testLang = QString::null ) {
01386 searchQuery = query;
01387 searchResults.clear();
01388 QString strippedQuery = query.stripWhiteSpace();
01389 if( !strippedQuery.isEmpty() )
01390 searchRec( strippedQuery, firstLang, testLang, vocabTree, searchResults );
01391 return( searchResults );
01392 }
01393
01394 void Controller::searchRec( const QString& query, const QString& firstLang, const QString& testLang, Folder* folder, QValueList<TermKey>& results ) {
01395 if( !folder || folder->isMarkedForDeletion() )
01396 return;
01397
01398 for( Base* child = folder->first(); child; child = folder->next() ) {
01399 if( strcmp( child->className(), "Vocabulary" ) == 0 ) {
01400 Vocabulary* childVocab = (Vocabulary*)child;
01401 searchRec( query, firstLang, testLang, childVocab, results );
01402 }
01403 else if( strcmp( child->className(), "Folder" ) == 0 ) {
01404 Folder* childFolder = (Folder*)child;
01405 searchRec( query, firstLang, testLang, childFolder, results );
01406 }
01407 }
01408
01409 }
01410
01411 void Controller::searchRec( const QString& query, const QString& firstLang, const QString& testLang, Vocabulary* vocab, QValueList<TermKey>& results ) {
01412 if( !vocab || vocab->isMarkedForDeletion() )
01413 return;
01414
01415 for( Vocabulary::TermMap::ConstIterator it = vocab->begin(); it != vocab->end(); it++ ) {
01416 const Term& term = *it;
01417 bool isStringFound = false;
01418
01419 if( prefs.isLanguageFilterEnabled() ) {
01420 if( term.isTranslationExists( firstLang ) && term.isTranslationExists( testLang ) ) {
01421 const Translation& firstLangTrans = term.getTranslation( firstLang );
01422 const Translation& testLangTrans = term.getTranslation( testLang );
01423 if( firstLangTrans.getWord().find( query ) != -1 || firstLangTrans.getAlt().find( query ) != -1 ||
01424 testLangTrans.getWord().find( query ) != -1 || testLangTrans.getAlt().find( query ) != -1 ) {
01425 isStringFound = true;
01426 }
01427 }
01428 }
01429 else {
01430 for( Term::TranslationMap::ConstIterator it2 = term.translationsBegin(); it2 != term.translationsEnd(); it2++ ) {
01431 const Translation& trans = it2.data();
01432 if( trans.getWord().find( query ) != -1 || trans.getAlt().find( query ) != -1 ) {
01433 isStringFound = true;
01434 break;
01435 }
01436 }
01437 }
01438
01439 if( !isStringFound ) {
01440 if( prefs.isLanguageFilterEnabled() ) {
01441 BilingualKey key( firstLang, testLang );
01442 if( term.isCommentExists( key ) && term.getComment( key ).find( query ) != -1 )
01443 isStringFound = true;
01444 }
01445 else {
01446 for( Term::CommentMap::ConstIterator it = term.commentsBegin(); it != term.commentsEnd(); it++ ) {
01447 const QString& comment = it.data();
01448 if( comment.find( query ) != -1 ) {
01449 isStringFound = true;
01450 break;
01451 }
01452 }
01453 }
01454 }
01455
01456 if( isStringFound ) {
01457 TermKey termKey( term.getId(), vocab->getId() );
01458 results.append( termKey );
01459 }
01460 }
01461 }
01462
01463 QValueList<TermKey> Controller::getSearchResults() const {
01464 return( searchResults );
01465 }
01466
01467 int Controller::getSearchResultsCount() const {
01468 return( searchResults.count() );
01469 }
01470
01471 bool Controller::deleteObsoleteData() {
01472 QDir applDir( applicationDirName );
01473 if( applDir.exists() ) {
01474 QStringList fileList = applDir.entryList( "*.dat.z" );
01475 for( QStringList::Iterator it = fileList.begin(); it != fileList.end(); it++ ) {
01476 QString filename = *it;
01477 if( filename.left( 5 ) != "quiz_" ) {
01478 if( !QFile::remove( applicationDirName + "/" + filename ) )
01479 return( false );
01480 }
01481 }
01482 }
01483 return( true );
01484 }