kfileitem.cpp
00001 /* This file is part of the KDE project 00002 Copyright (C) 1999 David Faure <faure@kde.org> 00003 2001 Carsten Pfeiffer <pfeiffer@kde.org> 00004 00005 This library is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Library General Public 00007 License as published by the Free Software Foundation; either 00008 version 2 of the License, or (at your option) any later version. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 Library General Public License for more details. 00014 00015 You should have received a copy of the GNU Library General Public License 00016 along with this library; see the file COPYING.LIB. If not, write to 00017 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00018 Boston, MA 02110-1301, USA. 00019 */ 00020 // $Id: kfileitem.cpp 717004 2007-09-25 20:52:46Z dfaure $ 00021 00022 #include <sys/time.h> 00023 #include <pwd.h> 00024 #include <grp.h> 00025 #include <sys/types.h> 00026 00027 #include <assert.h> 00028 #include <unistd.h> 00029 00030 #include "kfileitem.h" 00031 00032 #include <qdir.h> 00033 #include <qfile.h> 00034 #include <qmap.h> 00035 #include <qstylesheet.h> 00036 00037 #include <kdebug.h> 00038 #include <kfilemetainfo.h> 00039 #include <ksambashare.h> 00040 #include <knfsshare.h> 00041 #include <kglobal.h> 00042 #include <kglobalsettings.h> 00043 #include <kiconloader.h> 00044 #include <klargefile.h> 00045 #include <klocale.h> 00046 #include <kmimetype.h> 00047 #include <krun.h> 00048 00049 class KFileItem::KFileItemPrivate { 00050 public: 00051 QString iconName; 00052 }; 00053 00054 KFileItem::KFileItem( const KIO::UDSEntry& _entry, const KURL& _url, 00055 bool _determineMimeTypeOnDemand, bool _urlIsDirectory ) : 00056 m_entry( _entry ), 00057 m_url( _url ), 00058 m_pMimeType( 0 ), 00059 m_fileMode( KFileItem::Unknown ), 00060 m_permissions( KFileItem::Unknown ), 00061 m_bMarked( false ), 00062 m_bLink( false ), 00063 m_bIsLocalURL( _url.isLocalFile() ), 00064 m_bMimeTypeKnown( false ), 00065 m_hidden( Auto ), 00066 d(0) 00067 { 00068 readUDSEntry( _urlIsDirectory ); 00069 init( _determineMimeTypeOnDemand ); 00070 } 00071 00072 KFileItem::KFileItem( mode_t _mode, mode_t _permissions, const KURL& _url, bool _determineMimeTypeOnDemand ) : 00073 m_entry(), // warning ! 00074 m_url( _url ), 00075 m_strName( _url.fileName() ), 00076 m_strText( KIO::decodeFileName( m_strName ) ), 00077 m_pMimeType( 0 ), 00078 m_fileMode ( _mode ), 00079 m_permissions( _permissions ), 00080 m_bMarked( false ), 00081 m_bLink( false ), 00082 m_bIsLocalURL( _url.isLocalFile() ), 00083 m_bMimeTypeKnown( false ), 00084 m_hidden( Auto ), 00085 d(0) 00086 { 00087 init( _determineMimeTypeOnDemand ); 00088 } 00089 00090 KFileItem::KFileItem( const KURL &url, const QString &mimeType, mode_t mode ) 00091 : m_url( url ), 00092 m_strName( url.fileName() ), 00093 m_strText( KIO::decodeFileName( m_strName ) ), 00094 m_pMimeType( 0 ), 00095 m_fileMode( mode ), 00096 m_permissions( KFileItem::Unknown ), 00097 m_bMarked( false ), 00098 m_bLink( false ), 00099 m_bIsLocalURL( url.isLocalFile() ), 00100 m_bMimeTypeKnown( !mimeType.isEmpty() ), 00101 m_hidden( Auto ), 00102 d(0) 00103 { 00104 if (m_bMimeTypeKnown) 00105 m_pMimeType = KMimeType::mimeType( mimeType ); 00106 00107 init( false ); 00108 } 00109 00110 KFileItem::KFileItem( const KFileItem & item ) : 00111 d(0) 00112 { 00113 assign( item ); 00114 } 00115 00116 KFileItem& KFileItem::operator=( const KFileItem & item ) 00117 { 00118 assign( item ); 00119 return *this; 00120 } 00121 00122 KFileItem::~KFileItem() 00123 { 00124 delete d; 00125 } 00126 00127 void KFileItem::init( bool _determineMimeTypeOnDemand ) 00128 { 00129 m_access = QString::null; 00130 m_size = (KIO::filesize_t) -1; 00131 // metaInfo = KFileMetaInfo(); 00132 for ( int i = 0; i < NumFlags; i++ ) 00133 m_time[i] = (time_t) -1; 00134 00135 // determine mode and/or permissions if unknown 00136 if ( m_fileMode == KFileItem::Unknown || m_permissions == KFileItem::Unknown ) 00137 { 00138 mode_t mode = 0; 00139 if ( m_url.isLocalFile() ) 00140 { 00141 /* directories may not have a slash at the end if 00142 * we want to stat() them; it requires that we 00143 * change into it .. which may not be allowed 00144 * stat("/is/unaccessible") -> rwx------ 00145 * stat("/is/unaccessible/") -> EPERM H.Z. 00146 * This is the reason for the -1 00147 */ 00148 KDE_struct_stat buf; 00149 QCString path = QFile::encodeName(m_url.path( -1 )); 00150 if ( KDE_lstat( path.data(), &buf ) == 0 ) 00151 { 00152 mode = buf.st_mode; 00153 if ( S_ISLNK( mode ) ) 00154 { 00155 m_bLink = true; 00156 if ( KDE_stat( path.data(), &buf ) == 0 ) 00157 mode = buf.st_mode; 00158 else // link pointing to nowhere (see kio/file/file.cc) 00159 mode = (S_IFMT-1) | S_IRWXU | S_IRWXG | S_IRWXO; 00160 } 00161 // While we're at it, store the times 00162 m_time[ Modification ] = buf.st_mtime; 00163 m_time[ Access ] = buf.st_atime; 00164 if ( m_fileMode == KFileItem::Unknown ) 00165 m_fileMode = mode & S_IFMT; // extract file type 00166 if ( m_permissions == KFileItem::Unknown ) 00167 m_permissions = mode & 07777; // extract permissions 00168 } 00169 } 00170 } 00171 00172 // determine the mimetype 00173 if (!m_pMimeType && !m_url.isEmpty()) 00174 { 00175 bool accurate = false; 00176 bool isLocalURL; 00177 KURL url = mostLocalURL(isLocalURL); 00178 00179 m_pMimeType = KMimeType::findByURL( url, m_fileMode, isLocalURL, 00180 // use fast mode if not mimetype on demand 00181 _determineMimeTypeOnDemand, &accurate ); 00182 //kdDebug() << "finding mimetype for " << url.url() << " : " << m_pMimeType->name() << endl; 00183 // if we didn't use fast mode, or if we got a result, then this is the mimetype 00184 // otherwise, determineMimeType will be able to do better. 00185 m_bMimeTypeKnown = (!_determineMimeTypeOnDemand) || accurate; 00186 } 00187 } 00188 00189 void KFileItem::readUDSEntry( bool _urlIsDirectory ) 00190 { 00191 // extract the mode and the filename from the KIO::UDS Entry 00192 bool UDS_URL_seen = false; 00193 00194 KIO::UDSEntry::ConstIterator it = m_entry.begin(); 00195 for( ; it != m_entry.end(); ++it ) { 00196 switch ((*it).m_uds) { 00197 00198 case KIO::UDS_FILE_TYPE: 00199 m_fileMode = (mode_t)((*it).m_long); 00200 break; 00201 00202 case KIO::UDS_ACCESS: 00203 m_permissions = (mode_t)((*it).m_long); 00204 break; 00205 00206 case KIO::UDS_USER: 00207 m_user = ((*it).m_str); 00208 break; 00209 00210 case KIO::UDS_GROUP: 00211 m_group = ((*it).m_str); 00212 break; 00213 00214 case KIO::UDS_NAME: 00215 m_strName = (*it).m_str; 00216 m_strText = KIO::decodeFileName( m_strName ); 00217 break; 00218 00219 case KIO::UDS_URL: 00220 UDS_URL_seen = true; 00221 m_url = KURL((*it).m_str); 00222 if ( m_url.isLocalFile() ) 00223 m_bIsLocalURL = true; 00224 break; 00225 00226 case KIO::UDS_MIME_TYPE: 00227 m_pMimeType = KMimeType::mimeType((*it).m_str); 00228 m_bMimeTypeKnown = true; 00229 break; 00230 00231 case KIO::UDS_GUESSED_MIME_TYPE: 00232 m_guessedMimeType = (*it).m_str; 00233 break; 00234 00235 case KIO::UDS_LINK_DEST: 00236 m_bLink = !(*it).m_str.isEmpty(); // we don't store the link dest 00237 break; 00238 00239 case KIO::UDS_ICON_NAME: 00240 if ( !d ) 00241 d = new KFileItemPrivate(); 00242 d->iconName = (*it).m_str; 00243 break; 00244 00245 case KIO::UDS_HIDDEN: 00246 if ( (*it).m_long ) 00247 m_hidden = Hidden; 00248 else 00249 m_hidden = Shown; 00250 break; 00251 } 00252 } 00253 00254 // avoid creating these QStrings again and again 00255 static const QString& dot = KGlobal::staticQString("."); 00256 if ( _urlIsDirectory && !UDS_URL_seen && !m_strName.isEmpty() && m_strName != dot ) 00257 m_url.addPath( m_strName ); 00258 } 00259 00260 void KFileItem::refresh() 00261 { 00262 m_fileMode = KFileItem::Unknown; 00263 m_permissions = KFileItem::Unknown; 00264 m_pMimeType = 0L; 00265 m_user = QString::null; 00266 m_group = QString::null; 00267 m_metaInfo = KFileMetaInfo(); 00268 m_hidden = Auto; 00269 00270 // Basically, we can't trust any information we got while listing. 00271 // Everything could have changed... 00272 // Clearing m_entry makes it possible to detect changes in the size of the file, 00273 // the time information, etc. 00274 m_entry = KIO::UDSEntry(); 00275 init( false ); 00276 } 00277 00278 void KFileItem::refreshMimeType() 00279 { 00280 m_pMimeType = 0L; 00281 init( false ); // Will determine the mimetype 00282 } 00283 00284 void KFileItem::setURL( const KURL &url ) 00285 { 00286 m_url = url; 00287 setName( url.fileName() ); 00288 } 00289 00290 void KFileItem::setName( const QString& name ) 00291 { 00292 m_strName = name; 00293 m_strText = KIO::decodeFileName( m_strName ); 00294 } 00295 00296 QString KFileItem::linkDest() const 00297 { 00298 // Extract it from the KIO::UDSEntry 00299 KIO::UDSEntry::ConstIterator it = m_entry.begin(); 00300 for( ; it != m_entry.end(); ++it ) 00301 if ( (*it).m_uds == KIO::UDS_LINK_DEST ) 00302 return (*it).m_str; 00303 // If not in the KIO::UDSEntry, or if UDSEntry empty, use readlink() [if local URL] 00304 if ( m_bIsLocalURL ) 00305 { 00306 char buf[1000]; 00307 int n = readlink( QFile::encodeName(m_url.path( -1 )), buf, sizeof(buf)-1 ); 00308 if ( n != -1 ) 00309 { 00310 buf[ n ] = 0; 00311 return QFile::decodeName( buf ); 00312 } 00313 } 00314 return QString::null; 00315 } 00316 00317 QString KFileItem::localPath() const 00318 { 00319 if ( m_bIsLocalURL ) 00320 { 00321 return m_url.path(); 00322 } 00323 else 00324 { 00325 // Extract the local path from the KIO::UDSEntry 00326 KIO::UDSEntry::ConstIterator it = m_entry.begin(); 00327 const KIO::UDSEntry::ConstIterator end = m_entry.end(); 00328 for( ; it != end; ++it ) 00329 if ( (*it).m_uds == KIO::UDS_LOCAL_PATH ) 00330 return (*it).m_str; 00331 } 00332 00333 return QString::null; 00334 } 00335 00336 KIO::filesize_t KFileItem::size(bool &exists) const 00337 { 00338 exists = true; 00339 if ( m_size != (KIO::filesize_t) -1 ) 00340 return m_size; 00341 00342 // Extract it from the KIO::UDSEntry 00343 KIO::UDSEntry::ConstIterator it = m_entry.begin(); 00344 for( ; it != m_entry.end(); ++it ) 00345 if ( (*it).m_uds == KIO::UDS_SIZE ) { 00346 m_size = (*it).m_long; 00347 return m_size; 00348 } 00349 // If not in the KIO::UDSEntry, or if UDSEntry empty, use stat() [if local URL] 00350 if ( m_bIsLocalURL ) 00351 { 00352 KDE_struct_stat buf; 00353 if ( KDE_stat( QFile::encodeName(m_url.path( -1 )), &buf ) == 0 ) 00354 return buf.st_size; 00355 } 00356 exists = false; 00357 return 0L; 00358 } 00359 00360 bool KFileItem::hasExtendedACL() const 00361 { 00362 KIO::UDSEntry::ConstIterator it = m_entry.begin(); 00363 for( ; it != m_entry.end(); it++ ) 00364 if ( (*it).m_uds == KIO::UDS_EXTENDED_ACL ) { 00365 return true; 00366 } 00367 return false; 00368 } 00369 00370 KACL KFileItem::ACL() const 00371 { 00372 if ( hasExtendedACL() ) { 00373 // Extract it from the KIO::UDSEntry 00374 KIO::UDSEntry::ConstIterator it = m_entry.begin(); 00375 for( ; it != m_entry.end(); ++it ) 00376 if ( (*it).m_uds == KIO::UDS_ACL_STRING ) 00377 return KACL((*it).m_str); 00378 } 00379 // create one from the basic permissions 00380 return KACL( m_permissions ); 00381 } 00382 00383 KACL KFileItem::defaultACL() const 00384 { 00385 // Extract it from the KIO::UDSEntry 00386 KIO::UDSEntry::ConstIterator it = m_entry.begin(); 00387 for( ; it != m_entry.end(); ++it ) 00388 if ( (*it).m_uds == KIO::UDS_DEFAULT_ACL_STRING ) 00389 return KACL((*it).m_str); 00390 return KACL(); 00391 } 00392 00393 KIO::filesize_t KFileItem::size() const 00394 { 00395 bool exists; 00396 return size(exists); 00397 } 00398 00399 time_t KFileItem::time( unsigned int which ) const 00400 { 00401 bool hasTime; 00402 return time(which, hasTime); 00403 } 00404 time_t KFileItem::time( unsigned int which, bool &hasTime ) const 00405 { 00406 hasTime = true; 00407 unsigned int mappedWhich = 0; 00408 00409 switch( which ) { 00410 case KIO::UDS_MODIFICATION_TIME: 00411 mappedWhich = Modification; 00412 break; 00413 case KIO::UDS_ACCESS_TIME: 00414 mappedWhich = Access; 00415 break; 00416 case KIO::UDS_CREATION_TIME: 00417 mappedWhich = Creation; 00418 break; 00419 } 00420 00421 if ( m_time[mappedWhich] != (time_t) -1 ) 00422 return m_time[mappedWhich]; 00423 00424 // Extract it from the KIO::UDSEntry 00425 KIO::UDSEntry::ConstIterator it = m_entry.begin(); 00426 for( ; it != m_entry.end(); ++it ) 00427 if ( (*it).m_uds == which ) { 00428 m_time[mappedWhich] = static_cast<time_t>((*it).m_long); 00429 return m_time[mappedWhich]; 00430 } 00431 00432 // If not in the KIO::UDSEntry, or if UDSEntry empty, use stat() [if local URL] 00433 if ( m_bIsLocalURL ) 00434 { 00435 KDE_struct_stat buf; 00436 if ( KDE_stat( QFile::encodeName(m_url.path(-1)), &buf ) == 0 ) 00437 { 00438 if(which == KIO::UDS_CREATION_TIME) { 00439 // We can't determine creation time for local files 00440 hasTime = false; 00441 m_time[mappedWhich] = static_cast<time_t>(0); 00442 return m_time[mappedWhich]; 00443 } 00444 m_time[mappedWhich] = (which == KIO::UDS_MODIFICATION_TIME) ? 00445 buf.st_mtime : 00446 /* which == KIO::UDS_ACCESS_TIME)*/ 00447 buf.st_atime; 00448 return m_time[mappedWhich]; 00449 } 00450 } 00451 hasTime = false; 00452 return static_cast<time_t>(0); 00453 } 00454 00455 00456 QString KFileItem::user() const 00457 { 00458 if ( m_user.isEmpty() && m_bIsLocalURL ) 00459 { 00460 KDE_struct_stat buff; 00461 if ( KDE_lstat( QFile::encodeName(m_url.path( -1 )), &buff ) == 0) // get uid/gid of the link, if it's a link 00462 { 00463 struct passwd *user = getpwuid( buff.st_uid ); 00464 if ( user != 0L ) 00465 m_user = QString::fromLocal8Bit(user->pw_name); 00466 } 00467 } 00468 return m_user; 00469 } 00470 00471 QString KFileItem::group() const 00472 { 00473 #ifdef Q_OS_UNIX 00474 if (m_group.isEmpty() && m_bIsLocalURL ) 00475 { 00476 KDE_struct_stat buff; 00477 if ( KDE_lstat( QFile::encodeName(m_url.path( -1 )), &buff ) == 0) // get uid/gid of the link, if it's a link 00478 { 00479 struct group *ge = getgrgid( buff.st_gid ); 00480 if ( ge != 0L ) { 00481 m_group = QString::fromLocal8Bit(ge->gr_name); 00482 if (m_group.isEmpty()) 00483 m_group.sprintf("%d",ge->gr_gid); 00484 } else 00485 m_group.sprintf("%d",buff.st_gid); 00486 } 00487 } 00488 #endif 00489 return m_group; 00490 } 00491 00492 QString KFileItem::mimetype() const 00493 { 00494 KFileItem * that = const_cast<KFileItem *>(this); 00495 return that->determineMimeType()->name(); 00496 } 00497 00498 KMimeType::Ptr KFileItem::determineMimeType() 00499 { 00500 if ( !m_pMimeType || !m_bMimeTypeKnown ) 00501 { 00502 bool isLocalURL; 00503 KURL url = mostLocalURL(isLocalURL); 00504 00505 m_pMimeType = KMimeType::findByURL( url, m_fileMode, isLocalURL ); 00506 //kdDebug() << "finding mimetype for " << url.url() << " : " << m_pMimeType->name() << endl; 00507 m_bMimeTypeKnown = true; 00508 } 00509 00510 return m_pMimeType; 00511 } 00512 00513 bool KFileItem::isMimeTypeKnown() const 00514 { 00515 // The mimetype isn't known if determineMimeType was never called (on-demand determination) 00516 // or if this fileitem has a guessed mimetype (e.g. ftp symlink) - in which case 00517 // it always remains "not fully determined" 00518 return m_bMimeTypeKnown && m_guessedMimeType.isEmpty(); 00519 } 00520 00521 QString KFileItem::mimeComment() 00522 { 00523 KMimeType::Ptr mType = determineMimeType(); 00524 00525 bool isLocalURL; 00526 KURL url = mostLocalURL(isLocalURL); 00527 00528 QString comment = mType->comment( url, isLocalURL ); 00529 //kdDebug() << "finding comment for " << url.url() << " : " << m_pMimeType->name() << endl; 00530 if (!comment.isEmpty()) 00531 return comment; 00532 else 00533 return mType->name(); 00534 } 00535 00536 QString KFileItem::iconName() 00537 { 00538 if (d && (!d->iconName.isEmpty())) return d->iconName; 00539 00540 bool isLocalURL; 00541 KURL url = mostLocalURL(isLocalURL); 00542 00543 //kdDebug() << "finding icon for " << url.url() << " : " << m_pMimeType->name() << endl; 00544 return determineMimeType()->icon(url, isLocalURL); 00545 } 00546 00547 int KFileItem::overlays() const 00548 { 00549 int _state = 0; 00550 if ( m_bLink ) 00551 _state |= KIcon::LinkOverlay; 00552 00553 if ( !S_ISDIR( m_fileMode ) // Locked dirs have a special icon, use the overlay for files only 00554 && !isReadable()) 00555 _state |= KIcon::LockOverlay; 00556 00557 if ( isHidden() ) 00558 _state |= KIcon::HiddenOverlay; 00559 00560 if( S_ISDIR( m_fileMode ) && m_bIsLocalURL) 00561 { 00562 if (KSambaShare::instance()->isDirectoryShared( m_url.path() ) || 00563 KNFSShare::instance()->isDirectoryShared( m_url.path() )) 00564 { 00565 //kdDebug()<<"KFileShare::isDirectoryShared : "<<m_url.path()<<endl; 00566 _state |= KIcon::ShareOverlay; 00567 } 00568 } 00569 00570 if ( m_pMimeType->name() == "application/x-gzip" && m_url.fileName().right(3) == ".gz" ) 00571 _state |= KIcon::ZipOverlay; 00572 return _state; 00573 } 00574 00575 QPixmap KFileItem::pixmap( int _size, int _state ) const 00576 { 00577 if (d && (!d->iconName.isEmpty())) 00578 return DesktopIcon(d->iconName,_size,_state); 00579 00580 if ( !m_pMimeType ) 00581 { 00582 static const QString & defaultFolderIcon = 00583 KGlobal::staticQString(KMimeType::mimeType( "inode/directory" )->KServiceType::icon()); 00584 00585 if ( S_ISDIR( m_fileMode ) ) 00586 return DesktopIcon( defaultFolderIcon, _size, _state ); 00587 00588 return DesktopIcon( "unknown", _size, _state ); 00589 } 00590 00591 _state |= overlays(); 00592 00593 KMimeType::Ptr mime; 00594 // Use guessed mimetype if the main one hasn't been determined for sure 00595 if ( !m_bMimeTypeKnown && !m_guessedMimeType.isEmpty() ) 00596 mime = KMimeType::mimeType( m_guessedMimeType ); 00597 else 00598 mime = m_pMimeType; 00599 00600 // Support for gzipped files: extract mimetype of contained file 00601 // See also the relevant code in overlays, which adds the zip overlay. 00602 if ( mime->name() == "application/x-gzip" && m_url.fileName().right(3) == ".gz" ) 00603 { 00604 KURL sf; 00605 sf.setPath( m_url.path().left( m_url.path().length() - 3 ) ); 00606 //kdDebug() << "KFileItem::pixmap subFileName=" << subFileName << endl; 00607 mime = KMimeType::findByURL( sf, 0, m_bIsLocalURL ); 00608 } 00609 00610 bool isLocalURL; 00611 KURL url = mostLocalURL(isLocalURL); 00612 00613 QPixmap p = mime->pixmap( url, KIcon::Desktop, _size, _state ); 00614 //kdDebug() << "finding pixmap for " << url.url() << " : " << mime->name() << endl; 00615 if (p.isNull()) 00616 kdWarning() << "Pixmap not found for mimetype " << m_pMimeType->name() << endl; 00617 00618 return p; 00619 } 00620 00621 bool KFileItem::isReadable() const 00622 { 00623 /* 00624 struct passwd * user = getpwuid( geteuid() ); 00625 bool isMyFile = (QString::fromLocal8Bit(user->pw_name) == m_user); 00626 // This gets ugly for the group.... 00627 // Maybe we want a static QString for the user and a static QStringList 00628 // for the groups... then we need to handle the deletion properly... 00629 */ 00630 00631 if ( m_permissions != KFileItem::Unknown ) { 00632 // No read permission at all 00633 if ( !(S_IRUSR & m_permissions) && !(S_IRGRP & m_permissions) && !(S_IROTH & m_permissions) ) 00634 return false; 00635 00636 // Read permissions for all: save a stat call 00637 if ( (S_IRUSR|S_IRGRP|S_IROTH) & m_permissions ) 00638 return true; 00639 } 00640 00641 // Or if we can't read it [using ::access()] - not network transparent 00642 if ( m_bIsLocalURL && ::access( QFile::encodeName(m_url.path()), R_OK ) == -1 ) 00643 return false; 00644 00645 return true; 00646 } 00647 00648 bool KFileItem::isWritable() const 00649 { 00650 /* 00651 struct passwd * user = getpwuid( geteuid() ); 00652 bool isMyFile = (QString::fromLocal8Bit(user->pw_name) == m_user); 00653 // This gets ugly for the group.... 00654 // Maybe we want a static QString for the user and a static QStringList 00655 // for the groups... then we need to handle the deletion properly... 00656 */ 00657 00658 if ( m_permissions != KFileItem::Unknown ) { 00659 // No write permission at all 00660 if ( !(S_IWUSR & m_permissions) && !(S_IWGRP & m_permissions) && !(S_IWOTH & m_permissions) ) 00661 return false; 00662 } 00663 00664 // Or if we can't read it [using ::access()] - not network transparent 00665 if ( m_bIsLocalURL && ::access( QFile::encodeName(m_url.path()), W_OK ) == -1 ) 00666 return false; 00667 00668 return true; 00669 } 00670 00671 bool KFileItem::isHidden() const 00672 { 00673 if ( m_hidden != Auto ) 00674 return m_hidden == Hidden; 00675 00676 if ( !m_url.isEmpty() ) 00677 return m_url.fileName()[0] == '.'; 00678 else // should never happen 00679 return m_strName[0] == '.'; 00680 } 00681 00682 bool KFileItem::isDir() const 00683 { 00684 if ( m_fileMode == KFileItem::Unknown ) 00685 { 00686 kdDebug() << " KFileItem::isDir can't say -> false " << endl; 00687 return false; // can't say for sure, so no 00688 } 00689 return (S_ISDIR(m_fileMode)); 00690 /* 00691 if (!S_ISDIR(m_fileMode)) { 00692 if (m_url.isLocalFile()) { 00693 KMimeType::Ptr ptr=KMimeType::findByURL(m_url,0,true,true); 00694 if ((ptr!=0) && (ptr->is("directory/inode"))) return true; 00695 } 00696 return false 00697 } else return true;*/ 00698 } 00699 00700 bool KFileItem::acceptsDrops() 00701 { 00702 // A directory ? 00703 if ( S_ISDIR( mode() ) ) { 00704 return isWritable(); 00705 } 00706 00707 // But only local .desktop files and executables 00708 if ( !m_bIsLocalURL ) 00709 return false; 00710 00711 if ( mimetype() == "application/x-desktop") 00712 return true; 00713 00714 // Executable, shell script ... ? 00715 if ( ::access( QFile::encodeName(m_url.path()), X_OK ) == 0 ) 00716 return true; 00717 00718 return false; 00719 } 00720 00721 QString KFileItem::getStatusBarInfo() 00722 { 00723 QString text = m_strText; 00724 00725 if ( m_bLink ) 00726 { 00727 QString comment = determineMimeType()->comment( m_url, m_bIsLocalURL ); 00728 QString tmp; 00729 if ( comment.isEmpty() ) 00730 tmp = i18n ( "Symbolic Link" ); 00731 else 00732 tmp = i18n("%1 (Link)").arg(comment); 00733 text += "->"; 00734 text += linkDest(); 00735 text += " "; 00736 text += tmp; 00737 } 00738 else if ( S_ISREG( m_fileMode ) ) 00739 { 00740 bool hasSize; 00741 KIO::filesize_t sizeValue = size(hasSize); 00742 if(hasSize) 00743 text += QString(" (%1) ").arg( KIO::convertSize( sizeValue ) ); 00744 text += mimeComment(); 00745 } 00746 else if ( S_ISDIR ( m_fileMode ) ) 00747 { 00748 text += "/ "; 00749 text += mimeComment(); 00750 } 00751 else 00752 { 00753 text += " "; 00754 text += mimeComment(); 00755 } 00756 text.replace('\n', " "); // replace any newlines with a space, so the statusbar doesn't get a two-line string which messes the display up, Alex 00757 return text; 00758 } 00759 00760 QString KFileItem::getToolTipText(int maxcount) 00761 { 00762 // we can return QString::null if no tool tip should be shown 00763 QString tip; 00764 KFileMetaInfo info = metaInfo(); 00765 00766 // the font tags are a workaround for the fact that the tool tip gets 00767 // screwed if the color scheme uses white as default text color 00768 const char* start = "<tr><td><nobr><font color=\"black\">"; 00769 const char* mid = "</font></nobr></td><td><nobr><font color=\"black\">"; 00770 const char* end = "</font></nobr></td></tr>"; 00771 00772 tip = "<table cellspacing=0 cellpadding=0>"; 00773 00774 tip += start + i18n("Name:") + mid + text() + end; 00775 tip += start + i18n("Type:") + mid; 00776 00777 QString type = QStyleSheet::escape(mimeComment()); 00778 if ( m_bLink ) { 00779 tip += i18n("Link to %1 (%2)").arg(linkDest(), type) + end; 00780 } else 00781 tip += type + end; 00782 00783 if ( !S_ISDIR ( m_fileMode ) ) { 00784 bool hasSize; 00785 KIO::filesize_t sizeValue = size(hasSize); 00786 if(hasSize) 00787 tip += start + i18n("Size:") + mid + 00788 KIO::convertSizeWithBytes(sizeValue) + end; 00789 } 00790 QString timeStr = timeString( KIO::UDS_MODIFICATION_TIME); 00791 if(!timeStr.isEmpty()) 00792 tip += start + i18n("Modified:") + mid + 00793 timeStr + end; 00794 #ifndef Q_WS_WIN //TODO: show win32-specific permissions 00795 QString userStr = user(); 00796 QString groupStr = group(); 00797 if(!userStr.isEmpty() || !groupStr.isEmpty()) 00798 tip += start + i18n("Owner:") + mid + userStr + " - " + groupStr + end + 00799 start + i18n("Permissions:") + mid + 00800 parsePermissions(m_permissions) + end; 00801 #endif 00802 00803 if (info.isValid() && !info.isEmpty() ) 00804 { 00805 tip += "<tr><td colspan=2><center><s> </s></center></td></tr>"; 00806 QStringList keys = info.preferredKeys(); 00807 00808 // now the rest 00809 QStringList::Iterator it = keys.begin(); 00810 for (int count = 0; count<maxcount && it!=keys.end() ; ++it) 00811 { 00812 KFileMetaInfoItem item = info.item( *it ); 00813 if ( item.isValid() ) 00814 { 00815 QString s = item.string(); 00816 if ( ( item.attributes() & KFileMimeTypeInfo::SqueezeText ) 00817 && s.length() > 50) { 00818 s.truncate(47); 00819 s.append("..."); 00820 } 00821 if ( !s.isEmpty() ) 00822 { 00823 count++; 00824 tip += start + 00825 QStyleSheet::escape( item.translatedKey() ) + ":" + 00826 mid + 00827 QStyleSheet::escape( s ) + 00828 end; 00829 } 00830 00831 } 00832 } 00833 } 00834 tip += "</table>"; 00835 00836 //kdDebug() << "making this the tool tip rich text:\n"; 00837 //kdDebug() << tip << endl; 00838 00839 return tip; 00840 } 00841 00842 void KFileItem::run() 00843 { 00844 // It might be faster to pass skip that when we know the mimetype, 00845 // and just call KRun::runURL. But then we need to use mostLocalURL() 00846 // for application/x-desktop files, to be able to execute them. 00847 (void) new KRun( m_url, m_fileMode, m_bIsLocalURL ); 00848 } 00849 00850 bool KFileItem::cmp( const KFileItem & item ) 00851 { 00852 bool hasSize1,hasSize2,hasTime1,hasTime2; 00853 hasSize1 = hasSize2 = hasTime1 = hasTime2 = false; 00854 return ( m_strName == item.m_strName 00855 && m_bIsLocalURL == item.m_bIsLocalURL 00856 && m_fileMode == item.m_fileMode 00857 && m_permissions == item.m_permissions 00858 && m_user == item.m_user 00859 && m_group == item.m_group 00860 && m_bLink == item.m_bLink 00861 && m_hidden == item.m_hidden 00862 && size(hasSize1) == item.size(hasSize2) 00863 && hasSize1 == hasSize2 00864 && time(KIO::UDS_MODIFICATION_TIME, hasTime1) == item.time(KIO::UDS_MODIFICATION_TIME, hasTime2) 00865 && hasTime1 == hasTime2 00866 && (!d || !item.d || d->iconName == item.d->iconName) ); 00867 00868 // Don't compare the mimetypes here. They might not be known, and we don't want to 00869 // do the slow operation of determining them here. 00870 } 00871 00872 void KFileItem::assign( const KFileItem & item ) 00873 { 00874 if ( this == &item ) 00875 return; 00876 m_entry = item.m_entry; 00877 m_url = item.m_url; 00878 m_bIsLocalURL = item.m_bIsLocalURL; 00879 m_strName = item.m_strName; 00880 m_strText = item.m_strText; 00881 m_fileMode = item.m_fileMode; 00882 m_permissions = item.m_permissions; 00883 m_user = item.m_user; 00884 m_group = item.m_group; 00885 m_bLink = item.m_bLink; 00886 m_pMimeType = item.m_pMimeType; 00887 m_strLowerCaseName = item.m_strLowerCaseName; 00888 m_bMimeTypeKnown = item.m_bMimeTypeKnown; 00889 m_hidden = item.m_hidden; 00890 m_guessedMimeType = item.m_guessedMimeType; 00891 m_access = item.m_access; 00892 m_metaInfo = item.m_metaInfo; 00893 for ( int i = 0; i < NumFlags; i++ ) 00894 m_time[i] = item.m_time[i]; 00895 m_size = item.m_size; 00896 // note: m_extra is NOT copied, as we'd have no control over who is 00897 // deleting the data or not. 00898 00899 // We had a mimetype previously (probably), so we need to re-determine it 00900 determineMimeType(); 00901 00902 if ( item.d ) { 00903 if ( !d ) 00904 d = new KFileItemPrivate; 00905 d->iconName = item.d->iconName; 00906 } else { 00907 delete d; 00908 d = 0; 00909 } 00910 } 00911 00912 void KFileItem::setUDSEntry( const KIO::UDSEntry& _entry, const KURL& _url, 00913 bool _determineMimeTypeOnDemand, bool _urlIsDirectory ) 00914 { 00915 m_entry = _entry; 00916 m_url = _url; 00917 m_strName = QString::null; 00918 m_strText = QString::null; 00919 m_user = QString::null; 00920 m_group = QString::null; 00921 m_strLowerCaseName = QString::null; 00922 m_pMimeType = 0; 00923 m_fileMode = KFileItem::Unknown; 00924 m_permissions = KFileItem::Unknown; 00925 m_bMarked = false; 00926 m_bLink = false; 00927 m_bIsLocalURL = _url.isLocalFile(); 00928 m_bMimeTypeKnown = false; 00929 m_hidden = Auto; 00930 m_guessedMimeType = QString::null; 00931 m_metaInfo = KFileMetaInfo(); 00932 00933 if ( d ) 00934 d->iconName = QString::null; 00935 00936 readUDSEntry( _urlIsDirectory ); 00937 init( _determineMimeTypeOnDemand ); 00938 } 00939 00940 void KFileItem::setFileMode( mode_t m ) 00941 { 00942 m_fileMode = m; 00943 } 00944 00945 void KFileItem::setMimeType( const QString& mimetype ) 00946 { 00947 m_pMimeType = KMimeType::mimeType( mimetype ); 00948 } 00949 00950 void KFileItem::setExtraData( const void *key, void *value ) 00951 { 00952 if ( !key ) 00953 return; 00954 00955 m_extra.replace( key, value ); 00956 } 00957 00958 const void * KFileItem::extraData( const void *key ) const 00959 { 00960 QMapConstIterator<const void*,void*> it = m_extra.find( key ); 00961 if ( it != m_extra.end() ) 00962 return it.data(); 00963 return 0L; 00964 } 00965 00966 void * KFileItem::extraData( const void *key ) 00967 { 00968 QMapIterator<const void*,void*> it = m_extra.find( key ); 00969 if ( it != m_extra.end() ) 00970 return it.data(); 00971 return 0L; 00972 } 00973 00974 void KFileItem::removeExtraData( const void *key ) 00975 { 00976 m_extra.remove( key ); 00977 } 00978 00979 QString KFileItem::permissionsString() const 00980 { 00981 if (m_access.isNull()) 00982 m_access = parsePermissions( m_permissions ); 00983 00984 return m_access; 00985 } 00986 00987 QString KFileItem::parsePermissions(mode_t perm) const 00988 { 00989 char p[] = "---------- "; 00990 00991 if (isDir()) 00992 p[0]='d'; 00993 else if (isLink()) 00994 p[0]='l'; 00995 00996 if (perm & QFileInfo::ReadUser) 00997 p[1]='r'; 00998 if (perm & QFileInfo::WriteUser) 00999 p[2]='w'; 01000 if ((perm & QFileInfo::ExeUser) && !(perm & S_ISUID)) p[3]='x'; 01001 else if ((perm & QFileInfo::ExeUser) && (perm & S_ISUID)) p[3]='s'; 01002 else if (!(perm & QFileInfo::ExeUser) && (perm & S_ISUID)) p[3]='S'; 01003 01004 if (perm & QFileInfo::ReadGroup) 01005 p[4]='r'; 01006 if (perm & QFileInfo::WriteGroup) 01007 p[5]='w'; 01008 if ((perm & QFileInfo::ExeGroup) && !(perm & S_ISGID)) p[6]='x'; 01009 else if ((perm & QFileInfo::ExeGroup) && (perm & S_ISGID)) p[6]='s'; 01010 else if (!(perm & QFileInfo::ExeGroup) && (perm & S_ISGID)) p[6]='S'; 01011 01012 if (perm & QFileInfo::ReadOther) 01013 p[7]='r'; 01014 if (perm & QFileInfo::WriteOther) 01015 p[8]='w'; 01016 if ((perm & QFileInfo::ExeOther) && !(perm & S_ISVTX)) p[9]='x'; 01017 else if ((perm & QFileInfo::ExeOther) && (perm & S_ISVTX)) p[9]='t'; 01018 else if (!(perm & QFileInfo::ExeOther) && (perm & S_ISVTX)) p[9]='T'; 01019 01020 if (hasExtendedACL()) 01021 p[10]='+'; 01022 01023 return QString::fromLatin1(p); 01024 } 01025 01026 // check if we need to cache this 01027 QString KFileItem::timeString( unsigned int which ) const 01028 { 01029 bool hasTime; 01030 time_t time_ = time(which, hasTime); 01031 if(!hasTime) return QString::null; 01032 01033 QDateTime t; 01034 t.setTime_t( time_); 01035 return KGlobal::locale()->formatDateTime( t ); 01036 } 01037 01038 void KFileItem::setMetaInfo( const KFileMetaInfo & info ) 01039 { 01040 m_metaInfo = info; 01041 } 01042 01043 const KFileMetaInfo & KFileItem::metaInfo(bool autoget, int) const 01044 { 01045 bool isLocalURL; 01046 KURL url = mostLocalURL(isLocalURL); 01047 01048 if ( autoget && !m_metaInfo.isValid() && 01049 KGlobalSettings::showFilePreview(url) ) 01050 { 01051 m_metaInfo = KFileMetaInfo( url, mimetype() ); 01052 } 01053 01054 return m_metaInfo; 01055 } 01056 01057 KURL KFileItem::mostLocalURL(bool &local) const 01058 { 01059 QString local_path = localPath(); 01060 01061 if ( !local_path.isEmpty() ) 01062 { 01063 local = true; 01064 KURL url; 01065 url.setPath(local_path); 01066 return url; 01067 } 01068 else 01069 { 01070 local = m_bIsLocalURL; 01071 return m_url; 01072 } 01073 } 01074 01075 void KFileItem::virtual_hook( int, void* ) 01076 { /*BASE::virtual_hook( id, data );*/ } 01077 01078 QDataStream & operator<< ( QDataStream & s, const KFileItem & a ) 01079 { 01080 // We don't need to save/restore anything that refresh() invalidates, 01081 // since that means we can re-determine those by ourselves. 01082 s << a.m_url; 01083 s << a.m_strName; 01084 s << a.m_strText; 01085 return s; 01086 } 01087 01088 QDataStream & operator>> ( QDataStream & s, KFileItem & a ) 01089 { 01090 s >> a.m_url; 01091 s >> a.m_strName; 01092 s >> a.m_strText; 01093 a.m_bIsLocalURL = a.m_url.isLocalFile(); 01094 a.m_bMimeTypeKnown = false; 01095 a.refresh(); 01096 return s; 01097 }