/** Copyright (C) 2004-2005 Mickael Marchand This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "subversion_fileinfo.h" #include "subversion_core.h" #include #include #include #include #include #include #include #include #include #include #include SVNFileInfoProvider::SVNFileInfoProvider(subversionPart *parent, const char *name) : KDevVCSFileInfoProvider( parent, "svnfileinfoprovider" ), m_cachedDirEntries( 0 ), m_recursiveDirEntries(0) { Q_UNUSED(name); m_part = parent; } SVNFileInfoProvider::~SVNFileInfoProvider() { delete m_cachedDirEntries; m_cachedDirEntries = 0; delete m_recursiveDirEntries; m_recursiveDirEntries = 0; } //synchronous const VCSFileInfoMap *SVNFileInfoProvider::status( const TQString &dirPath ) { if ( !m_cachedDirEntries ) m_cachedDirEntries = new VCSFileInfoMap; // return m_cachedDirEntries; kdDebug(9036) << "svn provider : status " << dirPath << endl; if ( dirPath != m_previousDirPath ) { m_previousDirPath = dirPath; KURL servURL = "kdevsvn+http://fakeserver_this_is_normal_behavior/"; TQByteArray parms; TQDataStream s( parms, IO_WriteOnly ); int cmd = 9; TQString rPath = projectDirectory( ); rPath += TQDir::separator() + dirPath; kdDebug(9036) << "DIR : " << rPath << " " << KURL( TQFileInfo( rPath ).absFilePath() ) << endl; // s << cmd << KURL( TQFileInfo( rPath ).absFilePath() ) << true << true; //original line // Dukju Ahn: if checkRepos is set, status() accesses remote repository, // which causes significant delaym_owner especially when network speed is not fast enough. // Of course, the user cannot get information about the out-of-dateness of his local copy. s << cmd << KURL( TQFileInfo( rPath ).absFilePath() ) << false/*checkRepos*/ << false /*fullRecurse*/; TDEIO::SimpleJob *job2 = TDEIO::special(servURL, parms, false); job2->setWindow( m_part->mainWindow()->main() ); TQMap ma; TDEIO::NetAccess::synchronousRun(job2, m_part->mainWindow()->main(), 0, 0, &ma ); TQValueList keys = ma.keys(); qHeapSort( keys ); TQValueList::Iterator begin = keys.begin(), end = keys.end(), it; TQString path; int text_status = 0, prop_status = 0, repos_text_status = 0, repos_prop_status = 0; long int rev = 0; int curIdx, lastIdx; TQRegExp rx( "([0-9]*)(.*)" ); for ( it = begin; it != end; ) { kdDebug(9036) << "METADATA : " << *it << ":" << ma[ *it ] << endl; if ( rx.search( *it ) == -1 ) return m_cachedDirEntries; // something is wrong ! :) /* if some notification comes here, consume these notification metadatas */ if ( rx.cap( 2 ) == "action" ){ curIdx = lastIdx = rx.cap( 1 ).toInt(); while ( curIdx == lastIdx ){ ++it; if ( it == end ) break; if ( rx.search( *it ) == -1 ) continue; // something is wrong curIdx = rx.cap( 1 ).toInt(); } continue; } curIdx = lastIdx = rx.cap( 1 ).toInt(); while ( curIdx == lastIdx ) { if ( rx.cap( 2 ) == "path" ) path = ma[ *it ]; else if ( rx.cap( 2 ) == "text" ) text_status = ma[ *it ].toInt(); else if ( rx.cap( 2 ) == "prop" ) prop_status = ma[ *it ].toInt(); else if ( rx.cap( 2 ) == "reptxt" ) repos_text_status = ma[ *it ].toInt(); else if ( rx.cap( 2 ) == "repprop" ) repos_prop_status = ma[ *it ].toInt(); else if ( rx.cap( 2 ) == "rev" ) rev = ma[ *it ].toLong(); ++it; if ( it == end ) break; if ( rx.search( *it ) == -1 ) break; // something is wrong ! :) curIdx = rx.cap( 1 ).toInt(); } slotStatus(path, text_status, prop_status, repos_text_status, repos_prop_status, rev); } } kdDebug(9036) << " Returning VcsFileInfoMap. provider::status() finished " << endl; return m_cachedDirEntries; } bool SVNFileInfoProvider::requestStatus( const TQString &dirPath, void *callerData, bool recursive, bool checkRepos ) { kdDebug(9036) << "##################################################################################### svn provider : request status" << endl; m_savedCallerData = callerData; // Flush old cache if (m_cachedDirEntries) { delete m_cachedDirEntries; m_cachedDirEntries = 0; m_previousDirPath = dirPath; } TQByteArray parms; TQDataStream s( parms, IO_WriteOnly ); int cmd = 9; TQString rPath = projectDirectory( ); rPath += TQDir::separator() + dirPath; if( ! m_part->isValidDirectory( rPath ) ){ return false; } kdDebug(9036) << "DIR : " << rPath << " " << TQFileInfo( rPath ).absFilePath() << endl; s << cmd << KURL( TQFileInfo( rPath ).absFilePath() ) << checkRepos << recursive; KURL servURL = "kdevsvn+http://fakeserver_this_is_normal_behavior/"; job = TDEIO::special(servURL, parms, false); connect( job, TQT_SIGNAL( result( TDEIO::Job * ) ), this, TQT_SLOT( slotResult( TDEIO::Job * ) ) ); if( checkRepos ) m_part->svncore()->initProcessDlg( job, dirPath, i18n("Subversion File/Directory Status") ); return true; } void SVNFileInfoProvider::slotResult( TDEIO::Job *j ) { if ( j->error() ) j->showErrorDialog( m_part->mainWindow()->main() ); TDEIO::MetaData ma = j->metaData(); TQValueList keys = ma.keys(); qHeapSort( keys ); TQValueList::Iterator begin = keys.begin(), end = keys.end(), it; TQString path; int text_status = 0, prop_status = 0, repos_text_status = 0, repos_prop_status = 0; long int rev = 0; int curIdx, lastIdx; TQRegExp rx( "([0-9]*)(.*)" ); for ( it = begin; it != end; ) { kdDebug(9036) << "METADATA : " << *it << ":" << ma[ *it ] << endl; if ( rx.search( *it ) == -1 ) return; // something is wrong ! :) /* if some notification comes here, consume these notification metadatas */ if ( rx.cap( 2 ) == "action" ){ curIdx = lastIdx = rx.cap( 1 ).toInt(); while ( curIdx == lastIdx ){ ++it; if ( it == end ) break; if ( rx.search( *it ) == -1 ) continue; // something is wrong curIdx = rx.cap( 1 ).toInt(); } continue; } curIdx = lastIdx = rx.cap( 1 ).toInt(); while ( curIdx == lastIdx ) { if ( rx.cap( 2 ) == "path" ) path = ma[ *it ]; else if ( rx.cap( 2 ) == "text" ) text_status = ma[ *it ].toInt(); else if ( rx.cap( 2 ) == "prop" ) prop_status = ma[ *it ].toInt(); else if ( rx.cap( 2 ) == "reptxt" ) repos_text_status = ma[ *it ].toInt(); else if ( rx.cap( 2 ) == "repprop" ) repos_prop_status = ma[ *it ].toInt(); else if ( rx.cap( 2 ) == "rev" ) rev = ma[ *it ].toLong(); ++it; if ( it == end ) break; if ( rx.search( *it ) == -1 ) break; // something is wrong ! :) curIdx = rx.cap( 1 ).toInt(); } slotStatus(path, text_status, prop_status, repos_text_status, repos_prop_status, rev); } if ( m_cachedDirEntries ) emit statusReady(*m_cachedDirEntries, m_savedCallerData); } void SVNFileInfoProvider::slotStatus( const TQString& path,int text_status, int prop_status,int repos_text_status, int repos_prop_status, long int rev) { // kdDebug(9036) << "##################################################################################### svn provider : slotstatus" // << " path " << path << " text_status " << text_status << " prop_status " << prop_status << " repos_text_status " << repos_text_status // << " repos_prop_status " << repos_prop_status << " rev " << rev // << endl; if ( !m_cachedDirEntries ) m_cachedDirEntries = new VCSFileInfoMap; TQString wRev = TQString::number( rev ); //work rev TQString rRev = TQString::number( rev );// repo rev VCSFileInfo::FileState state = VCSFileInfo::Unknown; switch ( text_status ) { case 1: break; case 2: break; case 3: state = VCSFileInfo::Uptodate; break; case 4: state = VCSFileInfo::Added; break; case 5: break; case 6: //deleted state = VCSFileInfo::Deleted; break; case 7: //replaced state = VCSFileInfo::Replaced; break; case 8: //modified state = VCSFileInfo::Modified; break; case 9: //merged break; case 10: //conflicted state = VCSFileInfo::Conflict; break; case 11: //ignored break; case 12: //obstructed break; case 13: //external break; case 14: //incomplete break; } switch( prop_status ) { case 8: state = VCSFileInfo::Modified; break; } switch ( repos_text_status ) { case 1: break; case 2: break; case 3: break; case 4: break; case 5: break; case 6: //deleted break; case 7: //replaced break; case 8: //modified state = VCSFileInfo::NeedsPatch; break; case 9: //merged break; case 10: //conflicted break; case 11: //ignored break; case 12: //obstructed break; case 13: //external break; case 14: //incomplete break; } VCSFileInfo info(TQFileInfo( path ).fileName(),wRev,rRev,state); kdDebug(9036) << "Inserting " << info.toString() << endl; m_cachedDirEntries->insert( TQFileInfo( path ).fileName(), info); } TQString SVNFileInfoProvider::projectDirectory() const { return owner()->project()->projectDirectory(); } const VCSFileInfoMap *SVNFileInfoProvider::statusExt( const TQString &dirPath, bool checkRepos, bool fullRecurse, bool getAll, bool noIgnore ) { if ( !m_recursiveDirEntries ) m_recursiveDirEntries = new VCSFileInfoMap; // if ( dirPath != m_recursivePreviousDirPath ) { m_recursiveDirEntries->clear(); m_recursivePreviousDirPath = dirPath; KURL servURL = "kdevsvn+http://fakeserver_this_is_normal_behavior/"; TQByteArray parms; TQDataStream s( parms, IO_WriteOnly ); int cmd = 109; TQString rPath = projectDirectory( ); rPath += TQDir::separator() + dirPath; kdDebug(9036) << "DIR : " << rPath << " " << KURL( TQFileInfo( rPath ).absFilePath() ) << endl; s << cmd << checkRepos << fullRecurse << getAll << noIgnore << -1 << "WORKING" << KURL( TQFileInfo( rPath ).absFilePath() ); TDEIO::SimpleJob *job2 = TDEIO::special(servURL, parms, false); job2->setWindow( m_part->mainWindow()->main() ); TQMap ma; TDEIO::NetAccess::synchronousRun(job2, m_part->mainWindow()->main(), 0, 0, &ma ); TQValueList keys = ma.keys(); qHeapSort( keys ); TQValueList::Iterator begin = keys.begin(), end = keys.end(), it; TQString path; int text_status = 0, prop_status = 0, repos_text_status = 0, repos_prop_status = 0; long int rev = 0; int curIdx, lastIdx; TQRegExp rx( "([0-9]*)(.*)" ); for ( it = begin; it != end; ) { kdDebug(9036) << "METADATA : " << *it << ":" << ma[ *it ] << endl; if ( rx.search( *it ) == -1 ) return m_recursiveDirEntries; // something is wrong ! :) /* if some notification comes here, consume these notification metadatas */ if ( rx.cap( 2 ) == "action" ){ curIdx = lastIdx = rx.cap( 1 ).toInt(); while ( curIdx == lastIdx ){ ++it; if ( it == end ) break; if ( rx.search( *it ) == -1 ) continue; // something is wrong curIdx = rx.cap( 1 ).toInt(); } continue; } /* get properties */ curIdx = lastIdx = rx.cap( 1 ).toInt(); while ( curIdx == lastIdx ) { if ( rx.cap( 2 ) == "path" ) path = ma[ *it ]; else if ( rx.cap( 2 ) == "text" ) text_status = ma[ *it ].toInt(); else if ( rx.cap( 2 ) == "prop" ) prop_status = ma[ *it ].toInt(); else if ( rx.cap( 2 ) == "reptxt" ) repos_text_status = ma[ *it ].toInt(); else if ( rx.cap( 2 ) == "repprop" ) repos_prop_status = ma[ *it ].toInt(); else if ( rx.cap( 2 ) == "rev" ) rev = ma[ *it ].toLong(); ++it; if ( it == end ) break; if ( rx.search( *it ) == -1 ) break; // something is wrong ! :) curIdx = rx.cap( 1 ).toInt(); } slotStatusExt(dirPath, path, text_status, prop_status, repos_text_status, repos_prop_status, rev); } // } return m_recursiveDirEntries; } void SVNFileInfoProvider::slotStatusExt( const TQString& reqPath, const TQString& path,int text_status, int prop_status,int repos_text_status, int repos_prop_status, long int rev) { if ( !m_recursiveDirEntries ) m_recursiveDirEntries = new VCSFileInfoMap; TQString wRev = TQString::number( rev ); //work rev TQString rRev = TQString::number( rev );// repo rev VCSFileInfo::FileState state = VCSFileInfo::Unknown; switch ( text_status ) { case 1: // does not exist break; case 2: // unversioned break; case 3: state = VCSFileInfo::Uptodate; break; case 4: state = VCSFileInfo::Added; break; case 5: // missing break; case 6: //deleted state = VCSFileInfo::Deleted; break; case 7: //replaced state = VCSFileInfo::Replaced; break; case 8: //modified state = VCSFileInfo::Modified; break; case 9: //merged break; case 10: //conflicted state = VCSFileInfo::Conflict; break; case 11: //ignored break; case 12: //obstructed break; case 13: //external break; case 14: //incomplete break; } switch( prop_status ) { case 8: state = VCSFileInfo::Modified; break; } switch ( repos_text_status ) { case 1: break; case 2: break; case 3: break; case 4: break; case 5: break; case 6: //deleted break; case 7: //replaced break; case 8: //modified state = VCSFileInfo::NeedsPatch; break; case 9: //merged break; case 10: //conflicted break; case 11: //ignored break; case 12: //obstructed break; case 13: //external break; case 14: //incomplete break; } TQString relativeReqPath; if (reqPath == "./"){ // case of project top directory TQString reqAbsPath = projectDirectory(); if( path == reqAbsPath ){ //key of VCSInfo is project directory itself. So it is set to . relativeReqPath = "."; } else{ relativeReqPath = path.right( path.length() - reqAbsPath.length() - 1 ); } } else { TQString reqAbsPath = projectDirectory() + TQDir::separator() + reqPath; relativeReqPath = path.right( path.length() - reqAbsPath.length() - 1 ); if (relativeReqPath == reqAbsPath){ // case of requested directory itself. relativeReqPath = "."; } } VCSFileInfo info(relativeReqPath, wRev, rRev, state); m_recursiveDirEntries->insert( relativeReqPath, info ); // VCSFileInfo info(TQFileInfo( path ).fileName(),wRev,rRev,state); kdDebug(9036) << "Inserting " << info.toString() << endl; // m_recursiveDirEntries->insert( TQFileInfo( path ).fileName(), info); } #include "subversion_fileinfo.moc"