00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "searchfolder.h"
00020
00021 #include "queryserviceclient.h"
00022
00023 #include <Soprano/Vocabulary/Xesam>
00024 #include <Soprano/Vocabulary/NAO>
00025
00026 #include <Nepomuk/Variant>
00027
00028 #include <QtCore/QMutexLocker>
00029
00030 #include <KUrl>
00031 #include <KDebug>
00032 #include <KIO/Job>
00033 #include <KIO/NetAccess>
00034 #include <KUser>
00035 #include <kdirnotify.h>
00036 #include <qurlhash.h>
00037
00038 namespace {
00039 QString addCounterToFileName( const QString& name, int i )
00040 {
00041 QString newName( name );
00042
00043 int start = name.lastIndexOf('.');
00044 if (start != -1) {
00045
00046 newName.insert(start, QString::number( i ));
00047 }
00048 else {
00049
00050 newName += QString::number( i );
00051 }
00052 return newName;
00053 }
00054 }
00055
00056
00057 Nepomuk::SearchEntry::SearchEntry( const QUrl& res,
00058 const KIO::UDSEntry& uds )
00059 : m_resource( res ),
00060 m_entry( uds )
00061 {
00062 }
00063
00064
00065 Nepomuk::SearchFolder::SearchFolder()
00066 {
00067
00068 org::kde::KDirNotify::emitFilesAdded( "nepomuksearch:/" + m_name );
00069 }
00070
00071
00072 Nepomuk::SearchFolder::SearchFolder( const QString& name, const Search::Query& query, KIO::SlaveBase* slave )
00073 : QThread(),
00074 m_name( name ),
00075 m_query( query ),
00076 m_initialListingFinished( false ),
00077 m_slave( slave ),
00078 m_listEntries( false ),
00079 m_statingStarted( false )
00080 {
00081 kDebug() << name << QThread::currentThread();
00082 Q_ASSERT( !name.isEmpty() );
00083
00084 qRegisterMetaType<QList<QUrl> >();
00085 }
00086
00087
00088 Nepomuk::SearchFolder::~SearchFolder()
00089 {
00090 kDebug() << m_name << QThread::currentThread();
00091
00092
00093 quit();
00094 wait();
00095
00096 qDeleteAll( m_entries );
00097 }
00098
00099
00100 void Nepomuk::SearchFolder::run()
00101 {
00102 kDebug() << m_name << QThread::currentThread();
00103
00104 m_client = new Nepomuk::Search::QueryServiceClient();
00105
00106
00107
00108
00109
00110 connect( m_client, SIGNAL( newEntries( const QList<Nepomuk::Search::Result>& ) ),
00111 this, SLOT( slotNewEntries( const QList<Nepomuk::Search::Result>& ) ),
00112 Qt::DirectConnection );
00113 connect( m_client, SIGNAL( entriesRemoved( const QList<QUrl>& ) ),
00114 this, SLOT( slotEntriesRemoved( const QList<QUrl>& ) ),
00115 Qt::DirectConnection );
00116
00117
00118 connect( m_client, SIGNAL( finishedListing() ),
00119 this, SLOT( slotFinishedListing() ),
00120 Qt::QueuedConnection );
00121
00122 m_client->query( m_query );
00123 exec();
00124 delete m_client;
00125
00126 kDebug() << m_name << "done";
00127 }
00128
00129
00130 void Nepomuk::SearchFolder::list()
00131 {
00132 kDebug() << m_name << QThread::currentThread();
00133
00134 m_listEntries = !m_initialListingFinished;
00135 m_statEntry = false;
00136
00137 if ( !isRunning() ) {
00138 start();
00139 }
00140 else {
00141
00142 for ( QHash<QString, SearchEntry*>::const_iterator it = m_entries.constBegin();
00143 it != m_entries.constEnd(); ++it ) {
00144 m_slave->listEntry( ( *it )->entry(), false );
00145 }
00146
00147
00148 if ( m_initialListingFinished &&
00149 m_results.isEmpty() ) {
00150 m_slave->listEntry( KIO::UDSEntry(), true );
00151 m_slave->finished();
00152 }
00153 else {
00154 m_listEntries = true;
00155 }
00156 }
00157
00158
00159 if ( m_listEntries ) {
00160 if ( !m_statingStarted ) {
00161 QTimer::singleShot( 0, this, SLOT( slotStatNextResult() ) );
00162 }
00163 kDebug() << "entering loop" << m_name << QThread::currentThread();
00164 m_loop.exec();
00165 }
00166 }
00167
00168
00169 void Nepomuk::SearchFolder::stat( const QString& name )
00170 {
00171 kDebug() << name;
00172
00173 if ( SearchEntry* entry = findEntry( name ) ) {
00174 m_slave->statEntry( entry->entry() );
00175 m_slave->finished();
00176 }
00177 else if ( !isRunning() ||
00178 !m_results.isEmpty() ) {
00179 m_nameToStat = name;
00180 m_statEntry = true;
00181 m_listEntries = false;
00182
00183 if ( !isRunning() ) {
00184 start();
00185 }
00186
00187 if ( !m_statingStarted ) {
00188 QTimer::singleShot( 0, this, SLOT( slotStatNextResult() ) );
00189 }
00190 m_loop.exec();
00191 }
00192 else {
00193 m_slave->error( KIO::ERR_DOES_NOT_EXIST, "nepomuksearch:/" + m_name + '/' + name );
00194 }
00195 }
00196
00197
00198 Nepomuk::SearchEntry* Nepomuk::SearchFolder::findEntry( const QString& name ) const
00199 {
00200 kDebug() << name;
00201
00202 QHash<QString, SearchEntry*>::const_iterator it = m_entries.find( name );
00203 if ( it != m_entries.end() ) {
00204 kDebug() << "-----> found";
00205 return *it;
00206 }
00207 else {
00208 kDebug() << "-----> not found";
00209 return 0;
00210 }
00211 }
00212
00213
00214 Nepomuk::SearchEntry* Nepomuk::SearchFolder::findEntry( const KUrl& url ) const
00215 {
00216
00217 return 0;
00218 }
00219
00220
00221
00222 void Nepomuk::SearchFolder::slotNewEntries( const QList<Nepomuk::Search::Result>& results )
00223 {
00224 kDebug() << m_name << QThread::currentThread();
00225
00226 m_resultMutex.lock();
00227 m_results += results;
00228 m_resultMutex.unlock();
00229
00230 if ( m_initialListingFinished ) {
00231
00232 kDebug() << ( "Informing about change in folder nepomuksearch:/" + m_name );
00233 org::kde::KDirNotify::emitFilesAdded( "nepomuksearch:/" + m_name );
00234 }
00235 }
00236
00237
00238
00239 void Nepomuk::SearchFolder::slotEntriesRemoved( const QList<QUrl>& entries )
00240 {
00241 kDebug() << QThread::currentThread();
00242
00243 QMutexLocker lock( &m_resultMutex );
00244
00245 foreach( const QUrl& uri, entries ) {
00246 QHash<QUrl, QString>::iterator it = m_resourceNameMap.find( uri );
00247 if ( it != m_resourceNameMap.end() ) {
00248 delete m_entries.take( it.value() );
00249
00250
00251 org::kde::KDirNotify::emitFilesRemoved( QStringList() << ( "nepomuksearch:/" + m_name + '/' + *it ) );
00252
00253 m_resourceNameMap.erase( it );
00254 }
00255 }
00256 }
00257
00258
00259
00260 void Nepomuk::SearchFolder::slotFinishedListing()
00261 {
00262 kDebug() << m_name << QThread::currentThread();
00263 m_initialListingFinished = true;
00264 wrap();
00265 }
00266
00267
00268
00269 void Nepomuk::SearchFolder::slotStatNextResult()
00270 {
00271
00272 m_statingStarted = true;
00273
00274 while ( 1 ) {
00275
00276
00277
00278
00279 m_resultMutex.lock();
00280 if( !m_results.isEmpty() ) {
00281 Search::Result result = m_results.dequeue();
00282 m_resultMutex.unlock();
00283 SearchEntry* entry = statResult( result );
00284 if ( entry ) {
00285 if ( m_listEntries ) {
00286 kDebug() << "listing" << entry->resource();
00287 m_slave->listEntry( entry->entry(), false );
00288 }
00289 else if ( m_statEntry ) {
00290 if ( m_nameToStat == entry->entry().stringValue( KIO::UDSEntry::UDS_NAME ) ) {
00291 kDebug() << "stating" << entry->resource();
00292 m_nameToStat = QString();
00293 m_slave->statEntry( entry->entry() );
00294 }
00295 }
00296 }
00297 }
00298 else {
00299 m_resultMutex.unlock();
00300 break;
00301 }
00302 }
00303
00304 if ( !m_results.isEmpty() ||
00305 !m_initialListingFinished ) {
00306
00307
00308 QTimer::singleShot( 0, this, SLOT( slotStatNextResult() ) );
00309 }
00310 else {
00311 m_statingStarted = false;
00312 wrap();
00313 }
00314 }
00315
00316
00317
00318 void Nepomuk::SearchFolder::wrap()
00319 {
00320 kDebug() << m_name << QThread::currentThread();
00321
00322 if ( m_results.isEmpty() &&
00323 m_initialListingFinished &&
00324 m_loop.isRunning() ) {
00325 if ( m_listEntries ) {
00326 kDebug() << "listing done";
00327 m_slave->listEntry( KIO::UDSEntry(), true );
00328 m_slave->finished();
00329 }
00330 else if ( m_statEntry ) {
00331 if ( !m_nameToStat.isEmpty() ) {
00332
00333
00334 m_slave->error( KIO::ERR_DOES_NOT_EXIST, "nepomuksearch:/" + m_name + '/' + m_nameToStat );
00335 m_nameToStat = QString();
00336 }
00337 else
00338 m_slave->finished();
00339 }
00340
00341 m_statingStarted = false;
00342 m_listEntries = false;
00343 m_statEntry = false;
00344 kDebug() << m_name << QThread::currentThread() << "exiting loop";
00345 m_loop.exit();
00346 }
00347 }
00348
00349
00350
00351 Nepomuk::SearchEntry* Nepomuk::SearchFolder::statResult( const Search::Result& result )
00352 {
00353 kDebug() << result.resourceUri();
00354
00355 KIO::UDSEntry uds;
00356
00357 KUrl url = result[Soprano::Vocabulary::Xesam::url()].toString();
00358 if ( url.isEmpty() ) {
00359 url = result.resourceUri();
00360 }
00361 bool isFile = false;
00362 if ( !url.isEmpty() && url.scheme() != "akonadi" ) {
00363 kDebug() << "listing file" << url;
00364 if ( KIO::StatJob* job = KIO::stat( url, KIO::HideProgressInfo ) ) {
00365 job->setAutoDelete( false );
00366 if ( KIO::NetAccess::synchronousRun( job, 0 ) ) {
00367 uds = job->statResult();
00368 if ( url.isLocalFile() ) {
00369 uds.insert( KIO::UDSEntry::UDS_LOCAL_PATH, url.toLocalFile() );
00370 }
00371 isFile = true;
00372 }
00373 else {
00374 kDebug() << "failed to stat" << url;
00375 }
00376 delete job;
00377 }
00378 }
00379
00380
00381
00382
00383
00384
00385 if ( !isFile ) {
00386 kDebug() << "listing resource" << result.resourceUri();
00387
00388 Nepomuk::Resource res( result.resourceUri() );
00389
00390 QString name = res.genericLabel();
00391
00392
00393 if ( name.contains( '/' ) ) {
00394 name = name.section( '/', -1 );
00395 if ( name.isEmpty() )
00396 name = res.resourceUri().fragment();
00397 if ( name.isEmpty() )
00398 name = res.resourceUri().toString().replace( '/', '_' );
00399 }
00400
00401 uds.insert( KIO::UDSEntry::UDS_NAME, name );
00402 uds.insert( KIO::UDSEntry::UDS_DISPLAY_NAME, name );
00403
00404 QString icon = res.genericIcon();
00405 if ( !icon.isEmpty() ) {
00406 uds.insert( KIO::UDSEntry::UDS_ICON_NAME, icon );
00407 }
00408
00409 uds.insert( KIO::UDSEntry::UDS_CREATION_TIME, res.property( Soprano::Vocabulary::NAO::created() ).toDateTime().toTime_t() );
00410
00411 uds.insert( KIO::UDSEntry::UDS_ACCESS, 0700 );
00412 uds.insert( KIO::UDSEntry::UDS_USER, KUser().loginName() );
00413
00414
00415 uds.insert( KIO::UDSEntry::UDS_MIME_TYPE, "application/x-nepomuk-resource" );
00416 }
00417
00418 uds.insert( KIO::UDSEntry::UDS_TARGET_URL, result.resourceUri().toString() );
00419
00420
00421
00422
00423 QString name = uds.stringValue( KIO::UDSEntry::UDS_DISPLAY_NAME );
00424 if ( name.isEmpty() ) {
00425 name = uds.stringValue( KIO::UDSEntry::UDS_NAME );
00426 }
00427
00428
00429 if ( !name.isEmpty() ) {
00430 int cnt = 0;
00431 if ( m_nameCntHash.contains( name ) ) {
00432 cnt = ++m_nameCntHash[name];
00433 }
00434 else {
00435 cnt = m_nameCntHash[name] = 0;
00436 }
00437 if ( cnt >= 1 ) {
00438 name = addCounterToFileName( name, cnt );
00439 }
00440 uds.insert( KIO::UDSEntry::UDS_NAME, name );
00441 uds.insert( KIO::UDSEntry::UDS_DISPLAY_NAME, name );
00442
00443 SearchEntry* entry = new SearchEntry( result.resourceUri(), uds );
00444 m_entries.insert( name, entry );
00445 m_resourceNameMap.insert( result.resourceUri(), name );
00446
00447 kDebug() << "Stating" << result.resourceUri() << "done";
00448
00449 return entry;
00450 }
00451 else {
00452
00453 kDebug() << "Stating" << result.resourceUri() << "failed";
00454 return 0;
00455 }
00456 }