From 5d076b4455eace043f8c010b200700de33d1b7d2 Mon Sep 17 00:00:00 2001 From: Plamen Petrov Date: Sun, 17 Feb 2008 23:11:49 +0200 Subject: [PATCH] Fix both update_tree_view() and traverseUpdate_tree() A new private var is added for kmk - tree_needs_update - a bool, which should indicate that treeListView needs update after an "update". update_tree_view() was depending on specific data ordering - this fixes that, and now there is only one corner case where it may complain: if any of the TREE_BASEs are last in the file, there could be missing folders in the tree view. Even then, there is a qWarning() issued, advising a re-scan. traverseUpdate_tree() is now near a working state, but maybe it should try harder to imitate its parent - traverse_tree() - by remembering which is the last added item... This should happen in a later patch. --- src/kmk.cpp | 526 ++++++++++++++++++++++++++++++++++++++++++++++-------------- src/kmk.h | 1 + 2 files changed, 405 insertions(+), 122 deletions(-) diff --git a/src/kmk.cpp b/src/kmk.cpp index 8954707..d92c6fa 100644 --- a/src/kmk.cpp +++ b/src/kmk.cpp @@ -242,6 +242,7 @@ kmk::kmk() if( s->dbg() & KMK_DBG_SIGNALS ) kdDebug() << "constructor: done!" << endl; FileSaveCalledFromFileSaveAs = FALSE; + tree_needs_update = FALSE; QDir tmp_dir; tmp_dir.mkdir( "/tmp/kmk", TRUE ); @@ -1036,10 +1037,20 @@ void kmk::slotCatalogUpdateSubtree() // when the top is reached - the loop "break"s else break; } - kdDebug() << "slotCatalogUpdateSubtree: should update " << folder_name << endl; - kdDebug() << "slotCatalogUpdateSubtree: subDlevel shows " << subDlevel << "; zeroing it..." << endl; + if( s->dbg() & KMK_DBG_CAT_MEM_OPS ) + { + kdDebug() << "slotCatalogUpdateSubtree: should update " << folder_name << endl; + kdDebug() << "slotCatalogUpdateSubtree: subDlevel shows " << subDlevel << "; zeroing it..." << endl; + } subDlevel=0; traverseUpdate_tree( folder_name ); + if( tree_needs_update ) + { + tree_needs_update = FALSE; + update_tree_view(); + if( MusicCatalog.isEmpty() ) setCatalogStateAndUpdate( NoCatalog ); + else setCatalogStateAndUpdate( Modified ); + } } void kmk::slotTreeListViewPopupMenuRequested( QListViewItem* itm, const QPoint &pos, int col ) @@ -1071,6 +1082,7 @@ void kmk::slotTreeListViewCurrentChanged( QListViewItem * itm ) // kdDebug() << "(kmk):LVupdate: determine hole selected folder name time: " << ptime.elapsed() << " ms." << endl; // ptime.restart(); +// Find the MmData folder item and get the number of files it contains MmDataList::iterator it; bool found = FALSE; for ( it = MusicCatalog.begin(); it != MusicCatalog.end(); ++it ) @@ -1091,13 +1103,18 @@ void kmk::slotTreeListViewCurrentChanged( QListViewItem * itm ) // kdDebug() << "(kmk):LVupdate: table setup time: " << ptime.elapsed() << " ms." << endl; // ptime.restart(); +// If there are items, go to the next... if ( found ) { it++; +// ...and find the first MmData item, which is inside folder *p* +// The result should be files, because MmData folder's Folder() holds their full path, +// and there should be only one folder with *p* as Folder(), and we are already past that... while ( (( (*it).Folder().compare(p)!=0 )) ) it++; } QDateTime dt; KListViewItem * sel_item = 0; KListViewItem * new_item = (KListViewItem*) filesListView->firstChild(); +// This loop's main requirement is that files within a dir are consecutive for ( int k=0; kdbg() & KMK_DBG_CAT_MEM_OPS ) kdDebug() << "update_tree_view: starting..." << endl; - + if( MusicCatalog.isEmpty() ) + { + if( s->dbg() & KMK_DBG_CAT_MEM_OPS ) + kdDebug() << "update_tree_view: sorry, no data in catalog!" << endl; + return; + } // clear current contents of treeListView if( s->dbg() & KMK_DBG_CAT_MEM_OPS ) kdDebug() << "update_tree_view: clearing contents of treeListView...." << endl; @@ -1673,10 +1696,32 @@ void kmk::update_tree_view() MmDataList::iterator it; KListViewItem *ptr; + if( s->dbg() & KMK_DBG_CAT_MEM_OPS ) + { + kdDebug()<<"******* SHOWING MUSIC CATALOG DATA SEQUENTLY ********"<dbg() & KMK_DBG_CAT_MEM_OPS ) + kdDebug() << "update_tree_view: setting all dirs to [NOT ADDED]..." << endl; +// Go trough MusicCatalog and for each dir, set its BitRate() to 22 +// where non-zero value means that the dir is NOT in tree view and +// and should be added at the correct place + for ( it = MusicCatalog.begin(); it != MusicCatalog.end(); ++it ) + if ( (*it).IsDir() ) { (*it).setBitRate( 22 ); dirs++; } + for ( it = MusicCatalog.begin(); it != MusicCatalog.end(); ++it ) { -// look for a dir - if ( (*it).IsDir() ) +// look for a dir, that is NOT ADDED + if ( (*it).IsDir() && ( (*it).BitRate() > 0 ) ) { // when found one, if its parent is "TREE_BASE" - add it to the top... if ( (*it).Comment().compare( "TREE_BASE" )==0 ) @@ -1685,77 +1730,53 @@ void kmk::update_tree_view() kdDebug() << "update_tree_view: adding " << (*it).Folder() << " as a top-level TREE item..." << endl; ptr = new KListViewItem( (QListView*) treeListView, (*it).Folder() ); -// mark the new item as current + descend in it - cur_vlItem = ptr; +// and reflect the fact that its added to tree view + (*it).setBitRate( 0 ); + dirs--; + it = MusicCatalog.begin(); } // and if its not - find the location where the new one has to be added else { - if( (*it).Comment().isEmpty() ) - { - if( s->dbg() & KMK_DBG_CAT_MEM_OPS ) - kdDebug() << "update_tree_view: got a MmData folder with no comment - old format!!!!" << endl; - qWarning( "update_tree_view: OLD DATA FORMAT!!!!" ); - } - else - while ( TRUE ) { - // init *lv* to the last added item in the Tree view - QListViewItem* lv = cur_vlItem; + QListViewItemIterator trit( (QListView*) treeListView ); + while ( trit.current() ) + { + QListViewItem* lv = trit.current(); // this one will hold the full-blown path to the last added folder - QString folder_name; + QString folder_name; // this loop extracts a full path of the selected dir in the Tree view by // going from it to the top, collecting data on the way in *folder_name* - while ( TRUE ) { - folder_name.prepend( lv->text(0) ); - if( lv->parent() ) - { - if( lv->parent()->text(0).compare("/") != 0 ) folder_name.prepend( "/" ); - lv = lv->parent(); - } + while ( TRUE ) { + folder_name.prepend( lv->text(0) ); + if( lv->parent() ) + { + if( lv->parent()->text(0).compare("/") != 0 ) folder_name.prepend( "/" ); + lv = lv->parent(); + } // when the top is reached - the loop "break"s - else break; - } - if( s->dbg() & (KMK_DBG_CAT_MEM_OPS | KMK_DBG_OTHER ) ) - kdDebug() << "update_tree_view: previously added one is " << folder_name << endl; - // now we have the AbsPath() of the previously added folder; check if its the parent of the new one - if( (*it).Comment().compare( folder_name ) == 0 ) + else break; + } + if( (*it).Comment().compare( folder_name )==0 ) { if( s->dbg() & (KMK_DBG_CAT_MEM_OPS | KMK_DBG_OTHER ) ) - kdDebug() << "update_tree_view: adding " << (*it).FileName() << " as its child." << endl; - // and if it is - add it as a child of the previous folder ( pointed by cur_vlItem ) - ptr = new KListViewItem( (QListViewItem*) cur_vlItem, (*it).FileName() ); - // then descend in it / mark it as current - cur_vlItem = ptr; + kdDebug() << "update_tree_view: adding " << (*it).FileName() << "." << endl; + // and if it is - add it as a child of trit + ptr = new KListViewItem( (QListViewItem*) trit.current(), (*it).FileName() ); + // and reflect the fact that its added to tree view + (*it).setBitRate( 0 ); + dirs--; + it = MusicCatalog.begin(); break; } - else - { - if( s->dbg() & (KMK_DBG_CAT_MEM_OPS | KMK_DBG_OTHER ) ) - kdDebug() << "update_tree_view: moving up..." << endl; - if( cur_vlItem->parent() ) - { - if ( cur_vlItem->parent() != listViewRootItem ) - cur_vlItem = (KListViewItem*) cur_vlItem->parent(); - else - { - if( s->dbg() & KMK_DBG_CAT_MEM_OPS ) - kdDebug() << "update_tree_view: top level reached!!! Bailing out of loop..." << endl; - break; - } - } - else - { - if( s->dbg() & KMK_DBG_CAT_MEM_OPS ) - kdDebug() << "update_tree_view: !!!!!! no parent found for " - << cur_vlItem->text(0) << "!!!!!!!!!!!" << endl; - break; - } - } - } + ++trit; + } } } } - +// check if we added all the dirs... + if( dirs ) qWarning("Possible catalog incosistency detected!!! Better Re-Scan!!!"); + if( dirs && ( s->dbg() & KMK_DBG_CAT_MEM_OPS ) ) + kdDebug() << "update_tree_view: Possible catalog incosistency detected!!! Better Re-Scan!!!" << endl; // ok, we are done if( s->dbg() & KMK_DBG_CAT_MEM_OPS ) kdDebug() << "update_tree_view: done updating treeListView !" << endl; @@ -1764,26 +1785,51 @@ void kmk::update_tree_view() /* WARNING !!! OBSESIVE USE OF RECURSION!!!! */ +#define TUT "traverseUpdate_tree<"<: " unsigned long kmk::traverseUpdate_tree( const QString& dir ) { if(kmkSmooth->elapsed() >= _KMK_UPDATE_PERIOD) { kmkSmooth->restart(); qApp->processEvents(); } /* Here we mark our tree depth - subDlevel is a kmk private var */ subDlevel++; - kdDebug() << "traverseUpdate_tree: looking in " << dir << "..." << endl; + if( s->dbg() & KMK_DBG_CAT_MEM_OPS ) + kdDebug() << TUT"starting with param [" << dir << "]..." << endl; /* Create a QDir object, set to the "dir-for-scan" The filter is set to DIRECTORIEs, without symlinks */ QDir d ( dir ); -/// FIXME if dir does not exist, it and all its childer (folders and files) -/// FIXME should be wiped from MusicCatalog -/// NOTE if dir is the root in MusicCatalog (no items above it), the catalog -/// NOTE state should be set to NOCATALOG, and maybe - the catalog file - deleted + if( ! d.exists() ) + { + if( s->dbg() & KMK_DBG_CAT_MEM_OPS ) + { + kdDebug() << TUT"starting folder does NOT EXIST on drive;" << endl; + kdDebug() << TUT"removing it and all its children from catalog..." << endl; + } + MmDataList::iterator sm_mm; + QString qq1 = dir + "/"; + for ( sm_mm = MusicCatalog.begin(); sm_mm != MusicCatalog.end(); ++sm_mm ) + { + if ( ((*sm_mm).Folder().startsWith( qq1 ))||((*sm_mm).Folder().compare( dir )==0) ) + { + if( s->dbg() & KMK_DBG_CAT_MEM_OPS ) + kdDebug() << TUT"REMOVING FROM CATALOG ["<<(*sm_mm).FileName()<<"], Folder()=[" + <<(*sm_mm).Folder()<<"]..."<dbg() & KMK_DBG_FS_OPS ) + kdDebug() << TUT"finishing MAIN traverse_tree..." << endl; + subDlevel--; + return 0; + } d.setFilter( QDir::Dirs | QDir::NoSymLinks ); /* This gets our "dir-for-scan" subdirs' in @p list */ const QFileInfoList *list = d.entryInfoList(); QFileInfoListIterator it( *list ); /* @p fi is used to get the dir name and last modification time */ QFileInfo *fi = new QFileInfo( d.absPath() ); + QString parent_dir = d.absPath(); /* Create a new MmDataList entry with the extracted above data for the "dir-for-scan" and set @p new_dir to point at it; we need a pointer to this new item, because if we add any files, @@ -1792,8 +1838,7 @@ unsigned long kmk::traverseUpdate_tree( const QString& dir ) MmDataList::iterator checked_mm_dir; bool mmdir_found = FALSE; - if( s->dbg() & KMK_DBG_CAT_MEM_OPS ) - kdDebug() << "traverseUpdate_tree: Now will look for dir [" << dir << "]..." << endl; + bool dir_needs_update = FALSE; for ( checked_mm_dir = MusicCatalog.begin(); checked_mm_dir != MusicCatalog.end(); ++checked_mm_dir ) { if ( (*checked_mm_dir).IsDir() ) @@ -1801,22 +1846,41 @@ unsigned long kmk::traverseUpdate_tree( const QString& dir ) if ( (*checked_mm_dir).Folder().compare( dir )==0 ) { mmdir_found = TRUE; - if( s->dbg() & KMK_DBG_CAT_MEM_OPS ) - kdDebug() << "traverseUpdate_tree: ...found! " << endl; - kdDebug() << "traverseUpdate_tree: catalog FileSize() reads: " - << (*checked_mm_dir).FileSize() << endl; - kdDebug() << "traverseUpdate_tree: catalog Length() reads: " << (*checked_mm_dir).Length() << endl; - kdDebug() << "traverseUpdate_tree: current modified time reads: " - << fi->lastModified().toTime_t() << endl; - kdDebug() << "traverseUpdate_tree: catalog time reads: " << (*checked_mm_dir).ModifiedTime() << endl; if( fi->lastModified().toTime_t() != (*checked_mm_dir).ModifiedTime() ) - kdDebug() << "traverseUpdate_tree: modification times differ!!!!!" << endl; + dir_needs_update = TRUE; break; } } } -// MmDataList::iterator new_dir; + if( mmdir_found ) + parent_dir = (*checked_mm_dir).Comment(); + else + { + bool found = FALSE; + MmDataList::iterator ckit; + QString looked_for = dir; + looked_for.setLength( looked_for.length() - ( d.dirName().length() + 1 ) ); + for ( ckit = MusicCatalog.begin(); ckit != MusicCatalog.end(); ++ckit ) { + if ( (*ckit).IsDir() ) { + if ( (*ckit).Folder().compare( looked_for )==0 ) { found = TRUE; break; } + } + } + + if(found) parent_dir = looked_for; + else + { + parent_dir = "TREE_BASE"; + checked_mm_dir = MusicCatalog.begin(); + } + } + + if( s->dbg() & ( KMK_DBG_FS_OPS + KMK_DBG_CAT_MEM_OPS ) ) + { + kdDebug() << TUT"Checking STATUS of FOLDER [" << dir << "]..." << endl; + kdDebug() << TUT"parent_dir set to : [" << parent_dir << "]." << endl; + } + /* Some explanation : as we use the same elements to store info for audio files, and the dirs containing them - we do this trick: if the MmData item holds info on DIRECTORY - we set its fields like this: @@ -1826,26 +1890,85 @@ unsigned long kmk::traverseUpdate_tree( const QString& dir ) MmReadOnly - wether or not we have permission to write in DIR MmLength - set to the number of files in "dir-to-scan" subdirs MmFileSize - set to the number of files contained - updated later */ -/* MusicCatalog.append( MmData( d.absPath(), // folder - d.dirName(), // filename - "", // artist - "", // title - "", // album - "", // genre - "", // comment - 0, // year - 0, // track number - 0, // file size - updated later - fi->lastModified().toTime_t(), // modified time - fi->isWritable(), // read only? - we may use this to determine if we can "rename" dirs - TRUE, // is dir? - 0, // audio duration (length) in secs - upd. later - 0, // channels - 0, // samplerate - 0 ) ); // bitrate -*/ + MmData m = MmData( d.absPath(), // folder + d.dirName(), // filename + "", // artist + "", // title + "", // album + "", // genre + parent_dir, // comment + 0, // year + 0, // track number + 0, // file size - updated later + fi->lastModified().toTime_t(), // modified time + fi->isWritable(), // read only? - we may use this to determine if we can "rename" dirs + TRUE, // is dir? + 0, // audio duration (length) in secs - upd. later + 0, // channels + 0, // samplerate + 0 ); // bitrate +// If the dir is in catalog + if( mmdir_found ) + { +// And needs update (its changed on drive) + if( dir_needs_update ) + { +// Replace the outdated one with an actualized version +// Some of the fields actually are not up-to-date - they get updated at the end + if( checked_mm_dir==MusicCatalog.begin() ) +kdDebug()<dbg() & KMK_DBG_CAT_MEM_OPS ) + kdDebug() << TUT"IN catalog, NOT in SYNC" << endl; + } + else + { + if( s->dbg() & KMK_DBG_CAT_MEM_OPS ) + kdDebug() << TUT"IN catalog, IN SYNC" << endl; + } + } +// If the checked dir isn't in catalog - add it + else + { + for ( checked_mm_dir = MusicCatalog.begin(); checked_mm_dir != MusicCatalog.end(); ++checked_mm_dir ) + { +kdDebug()<=1) )&&(checked_mm_dir != MusicCatalog.end() )) + checked_mm_dir++; + + if( checked_mm_dir==MusicCatalog.end() ) +kdDebug()<dbg() & KMK_DBG_CAT_MEM_OPS ) + kdDebug() << TUT"NOT IN catalog, adding it..." << endl; + } /* We are done with @p fi for now - so, get rid of it */ delete fi; + + +kdDebug()< 0 ) { ptr->setOpen( FALSE ); ptr->setExpandable( TRUE ); } - kdDebug() << "traverseUpdate_tree: having " << lf << " files reported back..." << endl; } -// return lf; +// Now its time to remove folders, that are in catalog, but not on disk +// Walk on trough all folders in *dir*... + if ( !list->isEmpty() ) + { + MmDataList::iterator some_mm_dir; + bool found; + for ( some_mm_dir = MusicCatalog.begin(); some_mm_dir != MusicCatalog.end(); ++some_mm_dir ) + { +// Comment() field of MmData holds parent directory OR text "TREE_BASE" for folders + if ( ( (*some_mm_dir).IsDir() ) && ( (*some_mm_dir).Comment().compare( dir )==0 ) ) + { + if( s->dbg() & KMK_DBG_CAT_MEM_OPS ) + kdDebug() << TUT"Looking at [" << dir << "]'s subfolder..." << endl; + + found = FALSE; + QFileInfoListIterator it3( *list ); +// And if it has, we go over the list of "dir-for-scan" subdirs + while ( (fi = it3.current()) != 0 ) + { +// Check if these subdirs are not the FS reserved "." and ".." + if ( (fi->isReadable()) && (fi->isExecutable()) ) + if ( (fi->fileName().compare(".")!=0) && (fi->fileName().compare("..")!=0) ) + { +/* if( s->dbg() & KMK_DBG_CAT_MEM_OPS ) + kdDebug() << TUT"Found REAL folder [" << fi->absFilePath() << "]." << endl;*/ + if( fi->absFilePath().compare( (*some_mm_dir).Folder() )==0 ) + { +// When we find one, which is in catalog - mark it + found = TRUE; + break; + } + } +/* Go to the next file in "dir-for-scan"... */ + ++it3; + } + +/* if( s->dbg() & KMK_DBG_CAT_MEM_OPS ) + kdDebug() << TUT"Done listing." << endl;*/ + + if( found==FALSE ) + { + QString pftd = (*some_mm_dir).Folder(); // pftd == Parent Folder To Delete + QString pftd2 = pftd + "/"; + if( s->dbg() & KMK_DBG_CAT_MEM_OPS ) + { + kdDebug() << TUT"Folder [" << pftd <<"] is in catalog ONLY!" << endl; + kdDebug() << TUT"REMOVING it from catalog..." << endl; + } + MusicCatalog.remove( some_mm_dir ); + tree_needs_update = TRUE; + for ( some_mm_dir = MusicCatalog.begin(); some_mm_dir != MusicCatalog.end(); ++some_mm_dir ) + { + kdDebug() << TUT"Folder()=["<<(*some_mm_dir).Folder()<<"];"<=1) ) + if( ((*some_mm_dir).Folder().compare( pftd )==0) || ((*some_mm_dir).Folder().startsWith( pftd2 )) ) + { + if( s->dbg() & KMK_DBG_CAT_MEM_OPS ) + kdDebug() << TUT"REMOVING from CATALOG ["<<(*some_mm_dir).FileName()<<"], Folder()=[" + <<(*some_mm_dir).Folder()<<"]..."<dbg() & KMK_DBG_CAT_MEM_OPS ) + kdDebug() << TUT"Folder [" << (*some_mm_dir).FileName() + << "] is a real a sub-folder of [" << dir << "]." << endl; + } + } + } + + + MmDataList::iterator item_to_inset_at; +// These few lines should get a pointer to first file inside *dir* - the new ones should be +// added right on top of it + for ( item_to_inset_at = MusicCatalog.begin(); item_to_inset_at != MusicCatalog.end(); ++item_to_inset_at ) + { + if ( ( !(*item_to_inset_at).IsDir() ) && ( (*item_to_inset_at).Folder().compare( dir )==0 ) ) + { if( item_to_inset_at!=MusicCatalog.end() ) item_to_inset_at++; break; } + } /* Then we set our "dir-for-scan" filter to files, without symlinks */ d.setFilter( QDir::Files | QDir::NoSymLinks ); /* And get a list of its contents, after the filtering is apllied */ @@ -1900,7 +2104,8 @@ unsigned long kmk::traverseUpdate_tree( const QString& dir ) of files in a single directory - make sure we don't choke on someones huge collection, by using extra large counter.*/ unsigned long loaded_files = 0; - bool found_file; + bool found_file = FALSE; + bool file_needs_update = FALSE; MmDataList::iterator checked_mm_file; /* A cycle to iterate over the files in "dir-for-scan" */ while ( (fi2 = it2.current()) != 0 ) @@ -1924,45 +2129,62 @@ unsigned long kmk::traverseUpdate_tree( const QString& dir ) ( fi2->extension(FALSE).lower().compare("mpc") == 0 ) ) // muse-pack { found_file = FALSE; + file_needs_update = FALSE; if( s->dbg() & KMK_DBG_CAT_MEM_OPS ) - kdDebug() << "traverseUpdate_tree: Now will look for file [" << fi2->fileName() << "]..." << endl; + kdDebug() << TUT"Getting status of [" << fi2->fileName() << "]..." << endl; for ( checked_mm_file = MusicCatalog.begin(); checked_mm_file != MusicCatalog.end(); ++checked_mm_file ) { - if ( !(*checked_mm_file).IsDir() ) + if ( (*checked_mm_file).IsDir()==FALSE ) { if ( ( (*checked_mm_file).Folder().compare( dir )==0 ) && ( (*checked_mm_file).FileName().compare( fi2->fileName() )==0 ) ) { found_file = TRUE; - if( s->dbg() & KMK_DBG_CAT_MEM_OPS ) - kdDebug() << "traverseUpdate_tree: ... FILE found! " << endl; - kdDebug() << "traverseUpdate_tree: catalog FileSize() reads: " - << (*checked_mm_file).FileSize() << endl; - kdDebug() << "traverseUpdate_tree: catalog Length() reads: " - << (*checked_mm_file).Length() << endl; - kdDebug() << "traverseUpdate_tree: current modified time reads: " - << fi2->lastModified().toTime_t() << endl; - kdDebug() << "traverseUpdate_tree: catalog time reads: " - << (*checked_mm_file).ModifiedTime() << endl; if( fi2->lastModified().toTime_t() != (*checked_mm_file).ModifiedTime() ) - kdDebug() << "traverseUpdate_tree: modification times differ!!!!!" << endl; + file_needs_update = TRUE; break; } } } if( found_file ) { - kdDebug() << "traverseUpdate_tree: found file in catalog; MOVIN ON" << endl; - ++it2; - continue; + if( file_needs_update ) + { + if( s->dbg() & KMK_DBG_CAT_MEM_OPS ) + { + kdDebug() << TUT"IN catalog, NOT in SYNC..." << endl; + } + tree_needs_update = TRUE; +// Removing items from MmData's structures posibly invalidates all iterator, pointing at the +// deleted item, so we need to take care of that after the delete... + MusicCatalog.remove( checked_mm_file ); +// These few lines should get a pointer to first file inside *dir* - the new ones should be +// added right on top of it + for ( item_to_inset_at = MusicCatalog.begin(); + item_to_inset_at != MusicCatalog.end(); ++item_to_inset_at ) + { + if ( ( !(*item_to_inset_at).IsDir() ) && ( (*item_to_inset_at).Folder().compare( dir )==0 ) ) + { if( item_to_inset_at!=MusicCatalog.end() ) item_to_inset_at++; break; } + } + } + else + { + if( s->dbg() & KMK_DBG_CAT_MEM_OPS ) + kdDebug() << TUT"IN catalog, IN SYNC" << endl; + loaded_files++; + ++it2; + continue; + } } + else if( s->dbg() & KMK_DBG_CAT_MEM_OPS ) + kdDebug() << TUT"NOT in catalog, ADDING it..." << endl; /* Init our storage for this file... */ art = ""; ttl = ""; alb = ""; gen = ""; cmt = ""; using namespace TagLib; /* Use TagLib's functions to extract meta data and audio properties; This tells TagLib to read tags, and be as fast as possible */ - if( s->dbg() & KMK_DBG_FS_OPS ) - kdDebug() << "traverseUpdate_tree: Now checking: " << d.filePath( fi2->fileName().latin1() ) << endl; + if( s->dbg() & ( KMK_DBG_FS_OPS + KMK_DBG_OTHER ) ) + kdDebug() << TUT"Now checking: [" << d.filePath( fi2->fileName().latin1() ) << "]..." << endl; TagLib::FileRef f( d.filePath( fi2->fileName().latin1() ), TRUE, TagLib::AudioProperties::Fast ); /* If TagLib found the file to be valid - then add it to the catalog. Maybe here would be a good place to update some global catalog stats, @@ -2005,7 +2227,8 @@ unsigned long kmk::traverseUpdate_tree( const QString& dir ) ni.setBitRate( f.audioProperties()->bitrate() ); /* Now, after we've filled our new catalog item - lets add it to the catalog list */ - MusicCatalog.append( ni ); + item_to_inset_at = MusicCatalog.insert( item_to_inset_at, ni ); + tree_needs_update = TRUE; /* We said we will keep track of loaded files number - do so */ loaded_files++; total_files++; } @@ -2013,6 +2236,57 @@ unsigned long kmk::traverseUpdate_tree( const QString& dir ) /* Go to the next file in "dir-for-scan"... */ ++it2; } + +// Now its time to remove files, that are in catalog, but not on disk +// Walk on trough all files in *dir*... + for ( checked_mm_file = MusicCatalog.begin(); checked_mm_file != MusicCatalog.end(); ++checked_mm_file ) + { + if ( ( (*checked_mm_file).IsDir()==FALSE ) && ( (*checked_mm_file).Folder().compare( dir )==0 ) ) + { + found_file = FALSE; + QFileInfoListIterator it3( *list2 ); + while ( (fi2 = it3.current()) != 0 ) + { +/* If the files aren't with the supported extensions - ignore them; + We call QFileInfo->extension(FALSE) because we need only chars after LAST '.' */ + if ( fi2->isReadable() ) + // LOSSLESS first + if ( ( fi2->extension(FALSE).lower().compare("wv" ) == 0 ) || // wav-pack + ( fi2->extension(FALSE).lower().compare("tta" ) == 0 ) || // true-audio + ( fi2->extension(FALSE).lower().compare("ape" ) == 0 ) || // monkey's audio +/* Is it correct for a FLAC file to have any other extension than "flac"? + For example - can it be named "my_audio_file.fla"? Ideas, advices.... */ + ( fi2->extension(FALSE).lower().compare("flac") == 0 ) || // flac + // LOSSY next + ( fi2->extension(FALSE).lower().compare("mp3") == 0 ) || // mp3 + ( fi2->extension(FALSE).lower().compare("ogg") == 0 ) || // ogg-vorbis + ( fi2->extension(FALSE).lower().compare("spx") == 0 ) || // ogg-speex + ( fi2->extension(FALSE).lower().compare("mpc") == 0 ) ) // muse-pack + { + if( fi2->fileName().compare( (*checked_mm_file).FileName() )==0 ) + { +// When we find one, which is in catalog - mark it + found_file = TRUE; + break; + } + } +/* Go to the next file in "dir-for-scan"... */ + ++it3; + } +// If the file *(*checked_mm_file)* is in catalog, but not in the list of file of *dir* +// - then its for DELETION from catalog + if( found_file==FALSE ) + { + if( s->dbg() & KMK_DBG_CAT_MEM_OPS ) + kdDebug() << TUT"REMOVING [" << (*checked_mm_file).FileName() + << "] from catalog..." << endl; + tree_needs_update = TRUE; + MusicCatalog.remove( checked_mm_file ); + checked_mm_file = MusicCatalog.begin(); + } + } + } + /* Now here is what we've got so far: o) new_dir - it is a pointer to the MmData item, containing the "dir-for-scan" directory info; @@ -2020,17 +2294,25 @@ unsigned long kmk::traverseUpdate_tree( const QString& dir ) o) lf - contains the number of files added from all "dir-for-scan" SUBDIRs; o) loaded_files - contains the number of files added from "dir-for-scan" itself; If any of the last two in the list above is non-zero... */ -// if ( loaded_files || lf ) + if ( loaded_files || lf ) /* ...we must update the MmData item, containing the info for "dir-for-scan" to comply with this: [ ...if a MmData item holds info for a directory, its MmFileSize field holds a count of the files contained in it, !!! NOT !!! including its subdirs. ] We also update our overall folder counter.*/ -// { (*new_dir).setFileSize( loaded_files ); (*new_dir).setLength( lf ); total_folders++; } + { (*checked_mm_dir).setFileSize( loaded_files ); (*checked_mm_dir).setLength( lf ); total_folders++; } /* If the sum of the last two is zero (0), or... lets put it this way - if both of them are zeros - then the first two ought to be removed; */ -// else ; + else + { + MusicCatalog.remove( checked_mm_dir ); + if( s->dbg() & KMK_DBG_CAT_MEM_OPS ) + kdDebug() << TUT"REMOVING FOLDER [" << (*checked_mm_dir).FileName() << "] from catalog..." << endl; + } /* We are done on this level - return subDlevel to where it was... */ + if(s->dbg() & KMK_DBG_FS_OPS ) + if(subDlevel != 1) kdDebug() << TUT"done!" << endl; + else kdDebug() << TUT"Finishing MAIN traverse_tree..." << endl; subDlevel--; /* And then return the sum of files in "dir-for-scan" and the files in its subdirectories.*/ diff --git a/src/kmk.h b/src/kmk.h index e984fb6..15d8cec 100644 --- a/src/kmk.h +++ b/src/kmk.h @@ -402,6 +402,7 @@ private: * the tree, described in the MmData structure, inside the Tree view */ void update_tree_view(); + bool tree_needs_update; unsigned long traverseUpdate_tree( const QString& dir ); void bytes_to_read_by_traverse( const QString& dir ); void generateListViewXML( const KListView *list, QDomDocument doc, QDomElement e ); -- 2.11.4.GIT