diff options
Diffstat (limited to 'tdeio/tdeio/tdefileitem.cpp')
-rw-r--r-- | tdeio/tdeio/tdefileitem.cpp | 1202 |
1 files changed, 1202 insertions, 0 deletions
diff --git a/tdeio/tdeio/tdefileitem.cpp b/tdeio/tdeio/tdefileitem.cpp new file mode 100644 index 000000000..bd043504a --- /dev/null +++ b/tdeio/tdeio/tdefileitem.cpp @@ -0,0 +1,1202 @@ +/* This file is part of the KDE project + Copyright (C) 1999 David Faure <faure@kde.org> + 2001 Carsten Pfeiffer <pfeiffer@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +// $Id$ + +#include <config.h> + +#include <sys/time.h> +#include <pwd.h> +#include <grp.h> +#include <sys/types.h> + +#include <assert.h> +#include <unistd.h> + +#include "tdefileitem.h" + +#include <tqdir.h> +#include <tqfile.h> +#include <tqmap.h> +#include <tqstylesheet.h> +#include <tqimage.h> + +#include <kdebug.h> +#include <tdefilemetainfo.h> +#include <ksambashare.h> +#include <knfsshare.h> +#include <kglobal.h> +#include <kglobalsettings.h> +#include <kiconloader.h> +#include <klargefile.h> +#include <klocale.h> +#include <kmimetype.h> +#include <krun.h> + +#ifdef HAVE_ELFICON +#include "tdelficon.h" +#endif // HAVE_ELFICON + +class KFileItem::KFileItemPrivate { + public: + TQString iconName; +}; + +KFileItem::KFileItem( const TDEIO::UDSEntry& _entry, const KURL& _url, + bool _determineMimeTypeOnDemand, bool _urlIsDirectory ) : + m_entry( _entry ), + m_url( _url ), + m_pMimeType( 0 ), + m_fileMode( KFileItem::Unknown ), + m_permissions( KFileItem::Unknown ), + m_bMarked( false ), + m_bLink( false ), + m_bIsLocalURL( _url.isLocalFile() ), + m_bMimeTypeKnown( false ), + m_hidden( Auto ), + d(0) +{ + readUDSEntry( _urlIsDirectory ); + init( _determineMimeTypeOnDemand ); +} + +KFileItem::KFileItem( mode_t _mode, mode_t _permissions, const KURL& _url, bool _determineMimeTypeOnDemand ) : + m_entry(), // warning ! + m_url( _url ), + m_strName( _url.fileName() ), + m_strText( TDEIO::decodeFileName( m_strName ) ), + m_pMimeType( 0 ), + m_fileMode ( _mode ), + m_permissions( _permissions ), + m_bMarked( false ), + m_bLink( false ), + m_bIsLocalURL( _url.isLocalFile() ), + m_bMimeTypeKnown( false ), + m_hidden( Auto ), + d(0) +{ + init( _determineMimeTypeOnDemand ); +} + +KFileItem::KFileItem( const KURL &url, const TQString &mimeType, mode_t mode ) +: m_url( url ), + m_strName( url.fileName() ), + m_strText( TDEIO::decodeFileName( m_strName ) ), + m_pMimeType( 0 ), + m_fileMode( mode ), + m_permissions( KFileItem::Unknown ), + m_bMarked( false ), + m_bLink( false ), + m_bIsLocalURL( url.isLocalFile() ), + m_bMimeTypeKnown( !mimeType.isEmpty() ), + m_hidden( Auto ), + d(0) +{ + if (m_bMimeTypeKnown) + m_pMimeType = KMimeType::mimeType( mimeType ); + + init( false ); +} + +KFileItem::KFileItem( const KFileItem & item ) : + d(0) +{ + assign( item ); +} + +KFileItem& KFileItem::operator=( const KFileItem & item ) +{ + assign( item ); + return *this; +} + +KFileItem::~KFileItem() +{ + delete d; +} + +void KFileItem::init( bool _determineMimeTypeOnDemand ) +{ + m_access = TQString::null; + m_size = (TDEIO::filesize_t) -1; + // metaInfo = KFileMetaInfo(); + for ( int i = 0; i < NumFlags; i++ ) + m_time[i] = (time_t) -1; + + // determine mode and/or permissions if unknown + if ( m_fileMode == KFileItem::Unknown || m_permissions == KFileItem::Unknown ) + { + mode_t mode = 0; + if ( m_url.isLocalFile() ) + { + /* directories may not have a slash at the end if + * we want to stat() them; it requires that we + * change into it .. which may not be allowed + * stat("/is/unaccessible") -> rwx------ + * stat("/is/unaccessible/") -> EPERM H.Z. + * This is the reason for the -1 + */ + KDE_struct_stat buf; + TQCString path = TQFile::encodeName(m_url.path( -1 )); + if ( KDE_lstat( path.data(), &buf ) == 0 ) + { + mode = buf.st_mode; + if ( S_ISLNK( mode ) ) + { + m_bLink = true; + if ( KDE_stat( path.data(), &buf ) == 0 ) + mode = buf.st_mode; + else // link pointing to nowhere (see tdeio/file/file.cc) + mode = (S_IFMT-1) | S_IRWXU | S_IRWXG | S_IRWXO; + } + // While we're at it, store the times + m_time[ Modification ] = buf.st_mtime; + m_time[ Access ] = buf.st_atime; + if ( m_fileMode == KFileItem::Unknown ) + m_fileMode = mode & S_IFMT; // extract file type + if ( m_permissions == KFileItem::Unknown ) + m_permissions = mode & 07777; // extract permissions + } + } + } + + // determine the mimetype + if (!m_pMimeType && !m_url.isEmpty()) + { + bool accurate = false; + bool isLocalURL; + KURL url = mostLocalURL(isLocalURL); + + m_pMimeType = KMimeType::findByURL( url, m_fileMode, isLocalURL, + // use fast mode if not mimetype on demand + _determineMimeTypeOnDemand, &accurate ); + //kdDebug() << "finding mimetype for " << url.url() << " : " << m_pMimeType->name() << endl; + // if we didn't use fast mode, or if we got a result, then this is the mimetype + // otherwise, determineMimeType will be able to do better. + m_bMimeTypeKnown = (!_determineMimeTypeOnDemand) || accurate; + } +} + +void KFileItem::readUDSEntry( bool _urlIsDirectory ) +{ + // extract the mode and the filename from the TDEIO::UDS Entry + bool UDS_URL_seen = false; + + if (&m_entry == NULL) return; + + TDEIO::UDSEntry::ConstIterator it = m_entry.begin(); + for( ; it != m_entry.end(); ++it ) { + switch ((*it).m_uds) { + + case TDEIO::UDS_FILE_TYPE: + m_fileMode = (mode_t)((*it).m_long); + break; + + case TDEIO::UDS_ACCESS: + m_permissions = (mode_t)((*it).m_long); + break; + + case TDEIO::UDS_USER: + m_user = ((*it).m_str); + break; + + case TDEIO::UDS_GROUP: + m_group = ((*it).m_str); + break; + + case TDEIO::UDS_NAME: + m_strName = (*it).m_str; + m_strText = TDEIO::decodeFileName( m_strName ); + break; + + case TDEIO::UDS_URL: + UDS_URL_seen = true; + m_url = KURL((*it).m_str); + if ( m_url.isLocalFile() ) + m_bIsLocalURL = true; + break; + + case TDEIO::UDS_MIME_TYPE: + m_pMimeType = KMimeType::mimeType((*it).m_str); + m_bMimeTypeKnown = true; + break; + + case TDEIO::UDS_GUESSED_MIME_TYPE: + m_guessedMimeType = (*it).m_str; + break; + + case TDEIO::UDS_LINK_DEST: + m_bLink = !(*it).m_str.isEmpty(); // we don't store the link dest + break; + + case TDEIO::UDS_ICON_NAME: + if ( !d ) + d = new KFileItemPrivate(); + d->iconName = (*it).m_str; + break; + + case TDEIO::UDS_HIDDEN: + if ( (*it).m_long ) + m_hidden = Hidden; + else + m_hidden = Shown; + break; + } + } + + // avoid creating these QStrings again and again + static const TQString& dot = TDEGlobal::staticQString("."); + if ( _urlIsDirectory && !UDS_URL_seen && !m_strName.isEmpty() && m_strName != dot ) + m_url.addPath( m_strName ); +} + +void KFileItem::refresh() +{ + m_fileMode = KFileItem::Unknown; + m_permissions = KFileItem::Unknown; + m_pMimeType = 0L; + m_user = TQString::null; + m_group = TQString::null; + m_metaInfo = KFileMetaInfo(); + m_hidden = Auto; + + // Basically, we can't trust any information we got while listing. + // Everything could have changed... + // Clearing m_entry makes it possible to detect changes in the size of the file, + // the time information, etc. + m_entry = TDEIO::UDSEntry(); + init( false ); +} + +void KFileItem::refreshMimeType() +{ + m_pMimeType = 0L; + init( false ); // Will determine the mimetype +} + +void KFileItem::setURL( const KURL &url ) +{ + m_url = url; + setName( url.fileName() ); +} + +void KFileItem::setName( const TQString& name ) +{ + m_strName = name; + m_strText = TDEIO::decodeFileName( m_strName ); +} + +TQString KFileItem::linkDest() const +{ + if (&m_entry == NULL) return TQString::null; + + // Extract it from the TDEIO::UDSEntry + TDEIO::UDSEntry::ConstIterator it = m_entry.begin(); + for( ; it != m_entry.end(); ++it ) + if ( (*it).m_uds == TDEIO::UDS_LINK_DEST ) + return (*it).m_str; + // If not in the TDEIO::UDSEntry, or if UDSEntry empty, use readlink() [if local URL] + if ( m_bIsLocalURL ) + { + char buf[1000]; + int n = readlink( TQFile::encodeName(m_url.path( -1 )), buf, sizeof(buf)-1 ); + if ( n != -1 ) + { + buf[ n ] = 0; + return TQFile::decodeName( buf ); + } + } + return TQString::null; +} + +TQString KFileItem::localPath() const +{ + if ( m_bIsLocalURL ) + { + return m_url.path(); + } + else + { + if (&m_entry == NULL) return TQString::null; + + // Extract the local path from the TDEIO::UDSEntry + TDEIO::UDSEntry::ConstIterator it = m_entry.begin(); + const TDEIO::UDSEntry::ConstIterator end = m_entry.end(); + for( ; it != end; ++it ) + if ( (*it).m_uds == TDEIO::UDS_LOCAL_PATH ) + return (*it).m_str; + } + + return TQString::null; +} + +TDEIO::filesize_t KFileItem::size(bool &exists) const +{ + exists = true; + if ( m_size != (TDEIO::filesize_t) -1 ) + return m_size; + + if (&m_entry == NULL) return 0L; + + // Extract it from the TDEIO::UDSEntry + TDEIO::UDSEntry::ConstIterator it = m_entry.begin(); + for( ; it != m_entry.end(); ++it ) + if ( (*it).m_uds == TDEIO::UDS_SIZE ) { + m_size = (*it).m_long; + return m_size; + } + // If not in the TDEIO::UDSEntry, or if UDSEntry empty, use stat() [if local URL] + if ( m_bIsLocalURL ) + { + KDE_struct_stat buf; + if ( KDE_stat( TQFile::encodeName(m_url.path( -1 )), &buf ) == 0 ) + return buf.st_size; + } + exists = false; + return 0L; +} + +bool KFileItem::hasExtendedACL() const +{ + if (&m_entry == NULL) return false; + TDEIO::UDSEntry::ConstIterator it = m_entry.begin(); + for( ; it != m_entry.end(); it++ ) + if ( (*it).m_uds == TDEIO::UDS_EXTENDED_ACL ) { + return true; + } + return false; +} + +KACL KFileItem::ACL() const +{ + if ( hasExtendedACL() ) { + if (&m_entry == NULL) return KACL( m_permissions ); + + // Extract it from the TDEIO::UDSEntry + TDEIO::UDSEntry::ConstIterator it = m_entry.begin(); + for( ; it != m_entry.end(); ++it ) + if ( (*it).m_uds == TDEIO::UDS_ACL_STRING ) + return KACL((*it).m_str); + } + // create one from the basic permissions + return KACL( m_permissions ); +} + +KACL KFileItem::defaultACL() const +{ + if (&m_entry == NULL) return KACL(); + + // Extract it from the TDEIO::UDSEntry + TDEIO::UDSEntry::ConstIterator it = m_entry.begin(); + for( ; it != m_entry.end(); ++it ) + if ( (*it).m_uds == TDEIO::UDS_DEFAULT_ACL_STRING ) + return KACL((*it).m_str); + return KACL(); +} + +TDEIO::filesize_t KFileItem::size() const +{ + bool exists; + return size(exists); +} + +time_t KFileItem::time( unsigned int which ) const +{ + bool hasTime; + return time(which, hasTime); +} +time_t KFileItem::time( unsigned int which, bool &hasTime ) const +{ + hasTime = true; + unsigned int mappedWhich = 0; + + switch( which ) { + case TDEIO::UDS_MODIFICATION_TIME: + mappedWhich = Modification; + break; + case TDEIO::UDS_ACCESS_TIME: + mappedWhich = Access; + break; + case TDEIO::UDS_CREATION_TIME: + mappedWhich = Creation; + break; + } + + if ( m_time[mappedWhich] != (time_t) -1 ) + return m_time[mappedWhich]; + + if (&m_entry == NULL) return static_cast<time_t>(0); + + // Extract it from the TDEIO::UDSEntry + TDEIO::UDSEntry::ConstIterator it = m_entry.begin(); + for( ; it != m_entry.end(); ++it ) + if ( (*it).m_uds == which ) { + m_time[mappedWhich] = static_cast<time_t>((*it).m_long); + return m_time[mappedWhich]; + } + + // If not in the TDEIO::UDSEntry, or if UDSEntry empty, use stat() [if local URL] + if ( m_bIsLocalURL ) + { + KDE_struct_stat buf; + if ( KDE_stat( TQFile::encodeName(m_url.path(-1)), &buf ) == 0 ) + { + if(which == TDEIO::UDS_CREATION_TIME) { + // We can't determine creation time for local files + hasTime = false; + m_time[mappedWhich] = static_cast<time_t>(0); + return m_time[mappedWhich]; + } + m_time[mappedWhich] = (which == TDEIO::UDS_MODIFICATION_TIME) ? + buf.st_mtime : + /* which == TDEIO::UDS_ACCESS_TIME)*/ + buf.st_atime; + return m_time[mappedWhich]; + } + } + hasTime = false; + return static_cast<time_t>(0); +} + + +TQString KFileItem::user() const +{ + if ( m_user.isEmpty() && m_bIsLocalURL ) + { + KDE_struct_stat buff; + if ( KDE_lstat( TQFile::encodeName(m_url.path( -1 )), &buff ) == 0) // get uid/gid of the link, if it's a link + { + struct passwd *user = getpwuid( buff.st_uid ); + if ( user != 0L ) + m_user = TQString::fromLocal8Bit(user->pw_name); + } + } + return m_user; +} + +TQString KFileItem::group() const +{ +#ifdef Q_OS_UNIX + if (m_group.isEmpty() && m_bIsLocalURL ) + { + KDE_struct_stat buff; + if ( KDE_lstat( TQFile::encodeName(m_url.path( -1 )), &buff ) == 0) // get uid/gid of the link, if it's a link + { + struct group *ge = getgrgid( buff.st_gid ); + if ( ge != 0L ) { + m_group = TQString::fromLocal8Bit(ge->gr_name); + if (m_group.isEmpty()) + m_group.sprintf("%d",ge->gr_gid); + } else + m_group.sprintf("%d",buff.st_gid); + } + } +#endif + return m_group; +} + +TQString KFileItem::mimetype() const +{ + KFileItem * that = const_cast<KFileItem *>(this); + return that->determineMimeType()->name(); +} + +KMimeType::Ptr KFileItem::determineMimeType() +{ + if ( !m_pMimeType || !m_bMimeTypeKnown ) + { + bool isLocalURL; + KURL url = mostLocalURL(isLocalURL); + + m_pMimeType = KMimeType::findByURL( url, m_fileMode, isLocalURL ); + //kdDebug() << "finding mimetype for " << url.url() << " : " << m_pMimeType->name() << endl; + m_bMimeTypeKnown = true; + } + + return m_pMimeType; +} + +bool KFileItem::isMimeTypeKnown() const +{ + // The mimetype isn't known if determineMimeType was never called (on-demand determination) + // or if this fileitem has a guessed mimetype (e.g. ftp symlink) - in which case + // it always remains "not fully determined" + return m_bMimeTypeKnown && m_guessedMimeType.isEmpty(); +} + +TQString KFileItem::mimeComment() +{ + KMimeType::Ptr mType = determineMimeType(); + + bool isLocalURL; + KURL url = mostLocalURL(isLocalURL); + + TQString comment = mType->comment( url, isLocalURL ); + //kdDebug() << "finding comment for " << url.url() << " : " << m_pMimeType->name() << endl; + if (!comment.isEmpty()) + return comment; + else + return mType->name(); +} + +TQString KFileItem::iconName() +{ + if (d && (!d->iconName.isEmpty())) return d->iconName; + + bool isLocalURL; + KURL url = mostLocalURL(isLocalURL); + + //kdDebug() << "finding icon for " << url.url() << " : " << m_pMimeType->name() << endl; + return determineMimeType()->icon(url, isLocalURL); +} + +int KFileItem::overlays() const +{ + int _state = 0; + if ( m_bLink ) + _state |= KIcon::LinkOverlay; + + if ( !S_ISDIR( m_fileMode ) // Locked dirs have a special icon, use the overlay for files only + && !isReadable()) + _state |= KIcon::LockOverlay; + + if ( isHidden() ) + _state |= KIcon::HiddenOverlay; + + if( S_ISDIR( m_fileMode ) && m_bIsLocalURL) + { + if (KSambaShare::instance()->isDirectoryShared( m_url.path() ) || + KNFSShare::instance()->isDirectoryShared( m_url.path() )) + { + //kdDebug()<<"KFileShare::isDirectoryShared : "<<m_url.path()<<endl; + _state |= KIcon::ShareOverlay; + } + } + + if ( m_pMimeType->name() == "application/x-gzip" && m_url.fileName().right(3) == ".gz" ) + _state |= KIcon::ZipOverlay; + return _state; +} + +TQPixmap KFileItem::pixmap( int _size, int _state ) const +{ + if (d && (!d->iconName.isEmpty())) + return DesktopIcon(d->iconName,_size,_state); + + if ( !m_pMimeType ) + { + static const TQString & defaultFolderIcon = + TDEGlobal::staticQString(KMimeType::mimeType( "inode/directory" )->KServiceType::icon()); + + if ( S_ISDIR( m_fileMode ) ) + return DesktopIcon( defaultFolderIcon, _size, _state ); + + return DesktopIcon( "unknown", _size, _state ); + } + + _state |= overlays(); + + KMimeType::Ptr mime; + // Use guessed mimetype if the main one hasn't been determined for sure + if ( !m_bMimeTypeKnown && !m_guessedMimeType.isEmpty() ) + mime = KMimeType::mimeType( m_guessedMimeType ); + else + mime = m_pMimeType; + + // Support for gzipped files: extract mimetype of contained file + // See also the relevant code in overlays, which adds the zip overlay. + if ( mime->name() == "application/x-gzip" && m_url.fileName().right(3) == ".gz" ) + { + KURL sf; + sf.setPath( m_url.path().left( m_url.path().length() - 3 ) ); + //kdDebug() << "KFileItem::pixmap subFileName=" << subFileName << endl; + mime = KMimeType::findByURL( sf, 0, m_bIsLocalURL ); + } + + bool isLocalURL; + KURL url = mostLocalURL(isLocalURL); + + TQPixmap p = mime->pixmap( url, KIcon::Desktop, _size, _state ); + //kdDebug() << "finding pixmap for " << url.url() << " : " << mime->name() << endl; + if (p.isNull()) + kdWarning() << "Pixmap not found for mimetype " << m_pMimeType->name() << endl; + + if ( mime->name() == "application/x-executable" ) { + // At first glance it might seem to be a good idea to + // look for .desktop files for this executable before resorting to the embedded icon + // in the same fashion as the minicli, but on close examination this is NOT A GOOD IDEA. + // Specifically it allows one executable to mimic another purely based on filename, + // which could at certain times fool any user regardless of experience level. +#ifdef HAVE_ELFICON + // Check for an embedded icon + unsigned int icon_size; + libr_icon *icon = NULL; + libr_file *handle = NULL; + libr_access_t access = LIBR_READ; + + if((handle = libr_open(const_cast<char*>(url.path().ascii()), access)) == NULL) + { + kdWarning() << "failed to open file" << url.path() << endl; + return p; + } + + icon_size = _size; + icon = libr_icon_geticon_bysize(handle, icon_size); + + // See if the embedded icon name matches any icon file names already on the system + // If it does, use the system icon instead of the embedded one + int iconresnamefound = 0; + iconentry *entry = NULL; + iconlist icons; + if(!get_iconlist(handle, &icons)) + { + // Failed to obtain a list of ELF icons + kdWarning() << "failed to obtain ELF icon: " << libr_errmsg() << endl; + + // See if there is a system icon we can use + TQString sysIconName = elf_get_resource(handle, ".metadata_sysicon"); + if (!sysIconName.isEmpty()) { + if (TDEGlobal::iconLoader()->iconPath(sysIconName.ascii(), 0, true) != "") { + p = DesktopIcon( sysIconName.ascii(), _size, _state ); + } + } + + libr_close(handle); + return p; + } + else { + while((entry = get_nexticon(&icons, entry)) != NULL) + { + if(icon == NULL) + { + // Try loading this icon as fallback + icon = libr_icon_geticon_byname(handle, entry->name); + } + if (TDEGlobal::iconLoader()->iconPath(entry->name, 0, true) != "") { + iconresnamefound = 1; + p = DesktopIcon( entry->name, _size, _state ); + break; + } + } + } + + if ((iconresnamefound == 0) && (icon)) { + // Extract the embedded icon + size_t icon_data_length; + char* icondata = libr_icon_malloc(icon, &icon_data_length); + p.loadFromData(static_cast<uchar*>(static_cast<void*>(icondata)), icon_data_length); // EVIL CAST + if (icon_size != 0) { + TQImage ip = p.convertToImage(); + ip = ip.smoothScale(icon_size, icon_size); + p.convertFromImage(ip); + } + free(icondata); + libr_icon_close(icon); + } + + libr_close(handle); +#endif // HAVE_ELFICON + } + + return p; +} + +bool KFileItem::isReadable() const +{ + /* + struct passwd * user = getpwuid( geteuid() ); + bool isMyFile = (TQString::fromLocal8Bit(user->pw_name) == m_user); + // This gets ugly for the group.... + // Maybe we want a static TQString for the user and a static QStringList + // for the groups... then we need to handle the deletion properly... + */ + + if ( m_permissions != KFileItem::Unknown ) { + // No read permission at all + if ( !(S_IRUSR & m_permissions) && !(S_IRGRP & m_permissions) && !(S_IROTH & m_permissions) ) + return false; + + // Read permissions for all: save a stat call + if ( (S_IRUSR|S_IRGRP|S_IROTH) & m_permissions ) + return true; + } + + // Or if we can't read it [using ::access()] - not network transparent + if ( m_bIsLocalURL && ::access( TQFile::encodeName(m_url.path()), R_OK ) == -1 ) + return false; + + return true; +} + +bool KFileItem::isWritable() const +{ + /* + struct passwd * user = getpwuid( geteuid() ); + bool isMyFile = (TQString::fromLocal8Bit(user->pw_name) == m_user); + // This gets ugly for the group.... + // Maybe we want a static TQString for the user and a static QStringList + // for the groups... then we need to handle the deletion properly... + */ + + if ( m_permissions != KFileItem::Unknown ) { + // No write permission at all + if ( !(S_IWUSR & m_permissions) && !(S_IWGRP & m_permissions) && !(S_IWOTH & m_permissions) ) + return false; + } + + // Or if we can't read it [using ::access()] - not network transparent + if ( m_bIsLocalURL && ::access( TQFile::encodeName(m_url.path()), W_OK ) == -1 ) + return false; + + return true; +} + +bool KFileItem::isHidden() const +{ + if ( m_hidden != Auto ) + return m_hidden == Hidden; + + if ( !m_url.isEmpty() ) + return m_url.fileName()[0] == '.'; + else // should never happen + return m_strName[0] == '.'; +} + +bool KFileItem::isDir() const +{ + if ( m_fileMode == KFileItem::Unknown ) + { + kdDebug() << " KFileItem::isDir can't say -> false " << endl; + return false; // can't say for sure, so no + } + return (S_ISDIR(m_fileMode)); +/* + if (!S_ISDIR(m_fileMode)) { + if (m_url.isLocalFile()) { + KMimeType::Ptr ptr=KMimeType::findByURL(m_url,0,true,true); + if ((ptr!=0) && (ptr->is("directory/inode"))) return true; + } + return false + } else return true;*/ +} + +bool KFileItem::acceptsDrops() +{ + // A directory ? + if ( S_ISDIR( mode() ) ) { + return isWritable(); + } + + // But only local .desktop files and executables + if ( !m_bIsLocalURL ) + return false; + + if (( mimetype() == "application/x-desktop") || + ( mimetype() == "media/builtin-mydocuments") || + ( mimetype() == "media/builtin-mycomputer") || + ( mimetype() == "media/builtin-mynetworkplaces") || + ( mimetype() == "media/builtin-printers") || + ( mimetype() == "media/builtin-trash") || + ( mimetype() == "media/builtin-webbrowser")) + return true; + + // Executable, shell script ... ? + if ( ::access( TQFile::encodeName(m_url.path()), X_OK ) == 0 ) + return true; + + return false; +} + +TQString KFileItem::getStatusBarInfo() +{ + TQString text = m_strText; + + if ( m_bLink ) + { + TQString comment = determineMimeType()->comment( m_url, m_bIsLocalURL ); + TQString tmp; + if ( comment.isEmpty() ) + tmp = i18n ( "Symbolic Link" ); + else + tmp = i18n("%1 (Link)").arg(comment); + text += "->"; + text += linkDest(); + text += " "; + text += tmp; + } + else if ( S_ISREG( m_fileMode ) ) + { + bool hasSize; + TDEIO::filesize_t sizeValue = size(hasSize); + if(hasSize) + text += TQString(" (%1) ").arg( TDEIO::convertSize( sizeValue ) ); + text += mimeComment(); + } + else if ( S_ISDIR ( m_fileMode ) ) + { + text += "/ "; + text += mimeComment(); + } + else + { + text += " "; + text += mimeComment(); + } + 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 + return text; +} + +TQString KFileItem::getToolTipText(int maxcount) +{ + // we can return TQString::null if no tool tip should be shown + TQString tip; + KFileMetaInfo info = metaInfo(); + + // the font tags are a workaround for the fact that the tool tip gets + // screwed if the color scheme uses white as default text color + const char* start = "<tr><td><nobr><font color=\"black\">"; + const char* mid = "</font></nobr></td><td><nobr><font color=\"black\">"; + const char* end = "</font></nobr></td></tr>"; + + tip = "<table cellspacing=0 cellpadding=0>"; + + tip += start + i18n("Name:") + mid + text() + end; + tip += start + i18n("Type:") + mid; + + TQString type = TQStyleSheet::escape(mimeComment()); + if ( m_bLink ) { + tip += i18n("Link to %1 (%2)").arg(linkDest(), type) + end; + } else + tip += type + end; + + if ( !S_ISDIR ( m_fileMode ) ) { + bool hasSize; + TDEIO::filesize_t sizeValue = size(hasSize); + if(hasSize) + tip += start + i18n("Size:") + mid + + TDEIO::convertSizeWithBytes(sizeValue) + end; + } + TQString timeStr = timeString( TDEIO::UDS_MODIFICATION_TIME); + if(!timeStr.isEmpty()) + tip += start + i18n("Modified:") + mid + + timeStr + end; +#ifndef Q_WS_WIN //TODO: show win32-specific permissions + TQString userStr = user(); + TQString groupStr = group(); + if(!userStr.isEmpty() || !groupStr.isEmpty()) + tip += start + i18n("Owner:") + mid + userStr + " - " + groupStr + end + + start + i18n("Permissions:") + mid + + parsePermissions(m_permissions) + end; +#endif + + if (info.isValid() && !info.isEmpty() ) + { + tip += "<tr><td colspan=2><center><s> </s></center></td></tr>"; + TQStringList keys = info.preferredKeys(); + + // now the rest + TQStringList::Iterator it = keys.begin(); + for (int count = 0; count<maxcount && it!=keys.end() ; ++it) + { + KFileMetaInfoItem item = info.item( *it ); + if ( item.isValid() ) + { + TQString s = item.string(); + if ( ( item.attributes() & KFileMimeTypeInfo::SqueezeText ) + && s.length() > 50) { + s.truncate(47); + s.append("..."); + } + if ( !s.isEmpty() ) + { + count++; + tip += start + + TQStyleSheet::escape( item.translatedKey() ) + ":" + + mid + + TQStyleSheet::escape( s ) + + end; + } + + } + } + } + tip += "</table>"; + + //kdDebug() << "making this the tool tip rich text:\n"; + //kdDebug() << tip << endl; + + return tip; +} + +void KFileItem::run() +{ + // It might be faster to pass skip that when we know the mimetype, + // and just call KRun::runURL. But then we need to use mostLocalURL() + // for application/x-desktop files, to be able to execute them. + (void) new KRun( m_url, m_fileMode, m_bIsLocalURL ); +} + +bool KFileItem::cmp( const KFileItem & item ) +{ + bool hasSize1,hasSize2,hasTime1,hasTime2; + hasSize1 = hasSize2 = hasTime1 = hasTime2 = false; + return ( m_strName == item.m_strName + && m_bIsLocalURL == item.m_bIsLocalURL + && m_fileMode == item.m_fileMode + && m_permissions == item.m_permissions + && m_user == item.m_user + && m_group == item.m_group + && m_bLink == item.m_bLink + && m_hidden == item.m_hidden + && size(hasSize1) == item.size(hasSize2) + && hasSize1 == hasSize2 + && time(TDEIO::UDS_MODIFICATION_TIME, hasTime1) == item.time(TDEIO::UDS_MODIFICATION_TIME, hasTime2) + && hasTime1 == hasTime2 + && (!d || !item.d || d->iconName == item.d->iconName) ); + + // Don't compare the mimetypes here. They might not be known, and we don't want to + // do the slow operation of determining them here. +} + +void KFileItem::assign( const KFileItem & item ) +{ + if ( this == &item ) + return; + m_entry = item.m_entry; + m_url = item.m_url; + m_bIsLocalURL = item.m_bIsLocalURL; + m_strName = item.m_strName; + m_strText = item.m_strText; + m_fileMode = item.m_fileMode; + m_permissions = item.m_permissions; + m_user = item.m_user; + m_group = item.m_group; + m_bLink = item.m_bLink; + m_pMimeType = item.m_pMimeType; + m_strLowerCaseName = item.m_strLowerCaseName; + m_bMimeTypeKnown = item.m_bMimeTypeKnown; + m_hidden = item.m_hidden; + m_guessedMimeType = item.m_guessedMimeType; + m_access = item.m_access; + m_metaInfo = item.m_metaInfo; + for ( int i = 0; i < NumFlags; i++ ) + m_time[i] = item.m_time[i]; + m_size = item.m_size; + // note: m_extra is NOT copied, as we'd have no control over who is + // deleting the data or not. + + // We had a mimetype previously (probably), so we need to re-determine it + determineMimeType(); + + if ( item.d ) { + if ( !d ) + d = new KFileItemPrivate; + d->iconName = item.d->iconName; + } else { + delete d; + d = 0; + } +} + +void KFileItem::setUDSEntry( const TDEIO::UDSEntry& _entry, const KURL& _url, + bool _determineMimeTypeOnDemand, bool _urlIsDirectory ) +{ + m_entry = _entry; + m_url = _url; + m_strName = TQString::null; + m_strText = TQString::null; + m_user = TQString::null; + m_group = TQString::null; + m_strLowerCaseName = TQString::null; + m_pMimeType = 0; + m_fileMode = KFileItem::Unknown; + m_permissions = KFileItem::Unknown; + m_bMarked = false; + m_bLink = false; + m_bIsLocalURL = _url.isLocalFile(); + m_bMimeTypeKnown = false; + m_hidden = Auto; + m_guessedMimeType = TQString::null; + m_metaInfo = KFileMetaInfo(); + + if ( d ) + d->iconName = TQString::null; + + readUDSEntry( _urlIsDirectory ); + init( _determineMimeTypeOnDemand ); +} + +void KFileItem::setFileMode( mode_t m ) +{ + m_fileMode = m; +} + +void KFileItem::setMimeType( const TQString& mimetype ) +{ + m_pMimeType = KMimeType::mimeType( mimetype ); +} + +void KFileItem::setExtraData( const void *key, void *value ) +{ + if ( !key ) + return; + + m_extra.replace( key, value ); +} + +const void * KFileItem::extraData( const void *key ) const +{ + TQMapConstIterator<const void*,void*> it = m_extra.find( key ); + if ( it != m_extra.end() ) + return it.data(); + return 0L; +} + +void * KFileItem::extraData( const void *key ) +{ + TQMapIterator<const void*,void*> it = m_extra.find( key ); + if ( it != m_extra.end() ) + return it.data(); + return 0L; +} + +void KFileItem::removeExtraData( const void *key ) +{ + m_extra.remove( key ); +} + +TQString KFileItem::permissionsString() const +{ + if (m_access.isNull()) + m_access = parsePermissions( m_permissions ); + + return m_access; +} + +TQString KFileItem::parsePermissions(mode_t perm) const +{ + char p[] = "---------- "; + + if (isDir()) + p[0]='d'; + else if (isLink()) + p[0]='l'; + + if (perm & TQFileInfo::ReadUser) + p[1]='r'; + if (perm & TQFileInfo::WriteUser) + p[2]='w'; + if ((perm & TQFileInfo::ExeUser) && !(perm & S_ISUID)) p[3]='x'; + else if ((perm & TQFileInfo::ExeUser) && (perm & S_ISUID)) p[3]='s'; + else if (!(perm & TQFileInfo::ExeUser) && (perm & S_ISUID)) p[3]='S'; + + if (perm & TQFileInfo::ReadGroup) + p[4]='r'; + if (perm & TQFileInfo::WriteGroup) + p[5]='w'; + if ((perm & TQFileInfo::ExeGroup) && !(perm & S_ISGID)) p[6]='x'; + else if ((perm & TQFileInfo::ExeGroup) && (perm & S_ISGID)) p[6]='s'; + else if (!(perm & TQFileInfo::ExeGroup) && (perm & S_ISGID)) p[6]='S'; + + if (perm & TQFileInfo::ReadOther) + p[7]='r'; + if (perm & TQFileInfo::WriteOther) + p[8]='w'; + if ((perm & TQFileInfo::ExeOther) && !(perm & S_ISVTX)) p[9]='x'; + else if ((perm & TQFileInfo::ExeOther) && (perm & S_ISVTX)) p[9]='t'; + else if (!(perm & TQFileInfo::ExeOther) && (perm & S_ISVTX)) p[9]='T'; + + if (hasExtendedACL()) + p[10]='+'; + + return TQString::fromLatin1(p); +} + +// check if we need to cache this +TQString KFileItem::timeString( unsigned int which ) const +{ + bool hasTime; + time_t time_ = time(which, hasTime); + if(!hasTime) return TQString::null; + + TQDateTime t; + t.setTime_t( time_); + return TDEGlobal::locale()->formatDateTime( t ); +} + +void KFileItem::setMetaInfo( const KFileMetaInfo & info ) +{ + m_metaInfo = info; +} + +const KFileMetaInfo & KFileItem::metaInfo(bool autoget, int) const +{ + bool isLocalURL; + KURL url = mostLocalURL(isLocalURL); + + if ( autoget && !m_metaInfo.isValid() && + TDEGlobalSettings::showFilePreview(url) ) + { + m_metaInfo = KFileMetaInfo( url, mimetype() ); + } + + return m_metaInfo; +} + +KURL KFileItem::mostLocalURL(bool &local) const +{ + TQString local_path = localPath(); + + if ( !local_path.isEmpty() ) + { + local = true; + KURL url; + url.setPath(local_path); + return url; + } + else + { + local = m_bIsLocalURL; + return m_url; + } +} + +void KFileItem::virtual_hook( int, void* ) +{ /*BASE::virtual_hook( id, data );*/ } + +TQDataStream & operator<< ( TQDataStream & s, const KFileItem & a ) +{ + // We don't need to save/restore anything that refresh() invalidates, + // since that means we can re-determine those by ourselves. + s << a.m_url; + s << a.m_strName; + s << a.m_strText; + return s; +} + +TQDataStream & operator>> ( TQDataStream & s, KFileItem & a ) +{ + s >> a.m_url; + s >> a.m_strName; + s >> a.m_strText; + a.m_bIsLocalURL = a.m_url.isLocalFile(); + a.m_bMimeTypeKnown = false; + a.refresh(); + return s; +} |