1 /* This file is part of the KDE project
2 Copyright (C) 1999-2006 David Faure <faure@kde.org>
3 2001 Carsten Pfeiffer <pfeiffer@kde.org>
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
21 #include "kfileitem.h"
28 #include <sys/types.h>
34 #include <QtCore/QDate>
35 #include <QtCore/QDir>
36 #include <QtCore/QFile>
37 #include <QtCore/QMap>
38 #include <QtGui/QApplication>
39 #include <QTextDocument>
42 #include <kfilemetainfo.h>
44 #include <kglobalsettings.h>
45 #include <kiconloader.h>
47 #include <kmimetype.h>
50 #include <kdesktopfile.h>
51 #include <kmountpoint.h>
52 #include <kconfiggroup.h>
54 #include <knfsshare.h>
55 #include <ksambashare.h>
58 class KFileItemPrivate
: public QSharedData
61 KFileItemPrivate(const KIO::UDSEntry
& entry
,
62 mode_t mode
, mode_t permissions
,
63 const KUrl
& itemOrDirUrl
,
65 bool delayedMimeTypes
)
74 m_permissions( permissions
),
77 m_bIsLocalUrl(itemOrDirUrl
.isLocalFile()),
78 m_bMimeTypeKnown( false ),
79 m_delayedMimeTypes( delayedMimeTypes
),
80 m_useIconNameCache(false),
83 if (entry
.count() != 0) {
84 readUDSEntry( urlIsDirectory
);
86 Q_ASSERT(!urlIsDirectory
);
87 m_strName
= itemOrDirUrl
.fileName();
88 m_strText
= KIO::decodeFileName( m_strName
);
98 * Computes the text and mode from the UDSEntry
99 * Called by constructor, but can be called again later
100 * Nothing does that anymore though (I guess some old KonqFileItem did)
101 * so it's not a protected method of the public class anymore.
105 KIO::filesize_t
size() const;
106 KDateTime
time( KFileItem::FileTimes which
) const;
107 void setTime(KFileItem::FileTimes which
, long long time_t_val
) const;
108 bool cmp( const KFileItemPrivate
& item
) const;
109 QString
user() const;
110 QString
group() const;
113 * Extracts the data from the UDSEntry member and updates the KFileItem
116 void readUDSEntry( bool _urlIsDirectory
);
119 * Parses the given permission set and provides it for access()
121 QString
parsePermissions( mode_t perm
) const;
124 * The UDSEntry that contains the data for this fileitem, if it came from a directory listing.
126 mutable KIO::UDSEntry m_entry
;
128 * The url of the file
133 * The text for this item, i.e. the file name without path,
138 * The text for this item, i.e. the file name without path, decoded
139 * ('%%' becomes '%', '%2F' becomes '/')
144 * The icon name for this item.
146 mutable QString m_iconName
;
149 * The filename in lower case (to speed up sorting)
151 mutable QString m_strLowerCaseName
;
154 * The mimetype of the file
156 mutable KMimeType::Ptr m_pMimeType
;
165 mode_t m_permissions
;
168 * Marked : see mark()
172 * Whether the file is a link
178 bool m_bIsLocalUrl
:1;
180 mutable bool m_bMimeTypeKnown
:1;
181 bool m_delayedMimeTypes
:1;
183 /** True if m_iconName should be used as cache. */
184 mutable bool m_useIconNameCache
:1;
186 // Auto: check leading dot.
187 enum { Auto
, Hidden
, Shown
} m_hidden
:3;
189 // For special case like link to dirs over FTP
190 QString m_guessedMimeType
;
191 mutable QString m_access
;
192 QMap
<const void*, void*> m_extra
; // DEPRECATED
193 mutable KFileMetaInfo m_metaInfo
;
195 enum { NumFlags
= KFileItem::CreationTime
+ 1 };
196 mutable KDateTime m_time
[3];
199 void KFileItemPrivate::init()
202 // metaInfo = KFileMetaInfo();
204 // determine mode and/or permissions if unknown
205 // TODO: delay this until requested
206 if ( m_fileMode
== KFileItem::Unknown
|| m_permissions
== KFileItem::Unknown
)
209 if ( m_url
.isLocalFile() )
211 /* directories may not have a slash at the end if
212 * we want to stat() them; it requires that we
213 * change into it .. which may not be allowed
214 * stat("/is/unaccessible") -> rwx------
215 * stat("/is/unaccessible/") -> EPERM H.Z.
216 * This is the reason for the -1
219 const QString path
= m_url
.toLocalFile( KUrl::RemoveTrailingSlash
);
220 if ( KDE::lstat( path
, &buf
) == 0 )
223 if ( S_ISLNK( mode
) )
226 if ( KDE::stat( path
, &buf
) == 0 )
228 else // link pointing to nowhere (see kio/file/file.cc)
229 mode
= (S_IFMT
-1) | S_IRWXU
| S_IRWXG
| S_IRWXO
;
231 // While we're at it, store the times
232 setTime(KFileItem::ModificationTime
, buf
.st_mtime
);
233 setTime(KFileItem::AccessTime
, buf
.st_atime
);
234 if ( m_fileMode
== KFileItem::Unknown
)
235 m_fileMode
= mode
& S_IFMT
; // extract file type
236 if ( m_permissions
== KFileItem::Unknown
)
237 m_permissions
= mode
& 07777; // extract permissions
239 kDebug() << path
<< "does not exist anymore";
245 void KFileItemPrivate::readUDSEntry( bool _urlIsDirectory
)
247 // extract fields from the KIO::UDS Entry
249 m_fileMode
= m_entry
.numberValue( KIO::UDSEntry::UDS_FILE_TYPE
);
250 m_permissions
= m_entry
.numberValue( KIO::UDSEntry::UDS_ACCESS
);
251 m_strName
= m_entry
.stringValue( KIO::UDSEntry::UDS_NAME
);
253 const QString displayName
= m_entry
.stringValue( KIO::UDSEntry::UDS_DISPLAY_NAME
);
254 if (!displayName
.isEmpty())
255 m_strText
= displayName
;
257 m_strText
= KIO::decodeFileName( m_strName
);
259 const QString urlStr
= m_entry
.stringValue( KIO::UDSEntry::UDS_URL
);
260 const bool UDS_URL_seen
= !urlStr
.isEmpty();
261 if ( UDS_URL_seen
) {
262 m_url
= KUrl( urlStr
);
263 if ( m_url
.isLocalFile() )
264 m_bIsLocalUrl
= true;
266 const QString mimeTypeStr
= m_entry
.stringValue( KIO::UDSEntry::UDS_MIME_TYPE
);
267 m_bMimeTypeKnown
= !mimeTypeStr
.isEmpty();
268 if ( m_bMimeTypeKnown
)
269 m_pMimeType
= KMimeType::mimeType( mimeTypeStr
);
271 m_guessedMimeType
= m_entry
.stringValue( KIO::UDSEntry::UDS_GUESSED_MIME_TYPE
);
272 m_bLink
= !m_entry
.stringValue( KIO::UDSEntry::UDS_LINK_DEST
).isEmpty(); // we don't store the link dest
274 const int hiddenVal
= m_entry
.numberValue( KIO::UDSEntry::UDS_HIDDEN
, -1 );
275 m_hidden
= hiddenVal
== 1 ? Hidden
: ( hiddenVal
== 0 ? Shown
: Auto
);
277 // avoid creating these QStrings again and again
278 static const QString
& dot
= KGlobal::staticQString(".");
279 if ( _urlIsDirectory
&& !UDS_URL_seen
&& !m_strName
.isEmpty() && m_strName
!= dot
)
280 m_url
.addPath( m_strName
);
285 inline //because it is used only in one place
286 KIO::filesize_t
KFileItemPrivate::size() const
288 // Extract it from the KIO::UDSEntry
289 long long fieldVal
= m_entry
.numberValue( KIO::UDSEntry::UDS_SIZE
, -1 );
290 if ( fieldVal
!= -1 ) {
294 // If not in the KIO::UDSEntry, or if UDSEntry empty, use stat() [if local URL]
295 if ( m_bIsLocalUrl
) {
297 if ( KDE::stat( m_url
.toLocalFile(KUrl::RemoveTrailingSlash
), &buf
) == 0 )
303 void KFileItemPrivate::setTime(KFileItem::FileTimes mappedWhich
, long long time_t_val
) const
305 m_time
[mappedWhich
].setTime_t(time_t_val
);
306 m_time
[mappedWhich
] = m_time
[mappedWhich
].toLocalZone(); // #160979
309 KDateTime
KFileItemPrivate::time( KFileItem::FileTimes mappedWhich
) const
311 if ( !m_time
[mappedWhich
].isNull() )
312 return m_time
[mappedWhich
];
314 // Extract it from the KIO::UDSEntry
315 long long fieldVal
= -1;
316 switch ( mappedWhich
) {
317 case KFileItem::ModificationTime
:
318 fieldVal
= m_entry
.numberValue( KIO::UDSEntry::UDS_MODIFICATION_TIME
, -1 );
320 case KFileItem::AccessTime
:
321 fieldVal
= m_entry
.numberValue( KIO::UDSEntry::UDS_ACCESS_TIME
, -1 );
323 case KFileItem::CreationTime
:
324 fieldVal
= m_entry
.numberValue( KIO::UDSEntry::UDS_CREATION_TIME
, -1 );
327 if ( fieldVal
!= -1 ) {
328 setTime(mappedWhich
, fieldVal
);
329 return m_time
[mappedWhich
];
332 // If not in the KIO::UDSEntry, or if UDSEntry empty, use stat() [if local URL]
336 if ( KDE::stat( m_url
.toLocalFile(KUrl::RemoveTrailingSlash
), &buf
) == 0 )
338 setTime(KFileItem::ModificationTime
, buf
.st_mtime
);
339 setTime(KFileItem::AccessTime
, buf
.st_atime
);
340 m_time
[KFileItem::CreationTime
] = KDateTime();
341 return m_time
[mappedWhich
];
347 inline //because it is used only in one place
348 bool KFileItemPrivate::cmp( const KFileItemPrivate
& item
) const
351 kDebug() << "Comparing" << m_url
<< "and" << item
.m_url
;
352 kDebug() << " name" << (m_strName
== item
.m_strName
);
353 kDebug() << " local" << (m_bIsLocalUrl
== item
.m_bIsLocalUrl
);
354 kDebug() << " mode" << (m_fileMode
== item
.m_fileMode
);
355 kDebug() << " perm" << (m_permissions
== item
.m_permissions
);
356 kDebug() << " UDS_USER" << (user() == item
.user());
357 kDebug() << " UDS_GROUP" << (group() == item
.group());
358 kDebug() << " UDS_EXTENDED_ACL" << (m_entry
.stringValue( KIO::UDSEntry::UDS_EXTENDED_ACL
) == item
.m_entry
.stringValue( KIO::UDSEntry::UDS_EXTENDED_ACL
));
359 kDebug() << " UDS_ACL_STRING" << (m_entry
.stringValue( KIO::UDSEntry::UDS_ACL_STRING
) == item
.m_entry
.stringValue( KIO::UDSEntry::UDS_ACL_STRING
));
360 kDebug() << " UDS_DEFAULT_ACL_STRING" << (m_entry
.stringValue( KIO::UDSEntry::UDS_DEFAULT_ACL_STRING
) == item
.m_entry
.stringValue( KIO::UDSEntry::UDS_DEFAULT_ACL_STRING
));
361 kDebug() << " m_bLink" << (m_bLink
== item
.m_bLink
);
362 kDebug() << " m_hidden" << (m_hidden
== item
.m_hidden
);
363 kDebug() << " size" << (size() == item
.size());
364 kDebug() << " ModificationTime" << (time(KFileItem::ModificationTime
) == item
.time(KFileItem::ModificationTime
));
365 kDebug() << " UDS_ICON_NAME" << (m_entry
.stringValue( KIO::UDSEntry::UDS_ICON_NAME
) == item
.m_entry
.stringValue( KIO::UDSEntry::UDS_ICON_NAME
));
367 return ( m_strName
== item
.m_strName
368 && m_bIsLocalUrl
== item
.m_bIsLocalUrl
369 && m_fileMode
== item
.m_fileMode
370 && m_permissions
== item
.m_permissions
371 && user() == item
.user()
372 && group() == item
.group()
373 && m_entry
.stringValue( KIO::UDSEntry::UDS_EXTENDED_ACL
) == item
.m_entry
.stringValue( KIO::UDSEntry::UDS_EXTENDED_ACL
)
374 && m_entry
.stringValue( KIO::UDSEntry::UDS_ACL_STRING
) == item
.m_entry
.stringValue( KIO::UDSEntry::UDS_ACL_STRING
)
375 && m_entry
.stringValue( KIO::UDSEntry::UDS_DEFAULT_ACL_STRING
) == item
.m_entry
.stringValue( KIO::UDSEntry::UDS_DEFAULT_ACL_STRING
)
376 && m_bLink
== item
.m_bLink
377 && m_hidden
== item
.m_hidden
378 && size() == item
.size()
379 && time(KFileItem::ModificationTime
) == item
.time(KFileItem::ModificationTime
)
380 && m_entry
.stringValue( KIO::UDSEntry::UDS_ICON_NAME
) == item
.m_entry
.stringValue( KIO::UDSEntry::UDS_ICON_NAME
)
383 // Don't compare the mimetypes here. They might not be known, and we don't want to
384 // do the slow operation of determining them here.
387 inline //because it is used only in one place
388 QString
KFileItemPrivate::parsePermissions(mode_t perm
) const
390 static char buffer
[ 12 ];
392 char uxbit
,gxbit
,oxbit
;
394 if ( (perm
& (S_IXUSR
|S_ISUID
)) == (S_IXUSR
|S_ISUID
) )
396 else if ( (perm
& (S_IXUSR
|S_ISUID
)) == S_ISUID
)
398 else if ( (perm
& (S_IXUSR
|S_ISUID
)) == S_IXUSR
)
403 if ( (perm
& (S_IXGRP
|S_ISGID
)) == (S_IXGRP
|S_ISGID
) )
405 else if ( (perm
& (S_IXGRP
|S_ISGID
)) == S_ISGID
)
407 else if ( (perm
& (S_IXGRP
|S_ISGID
)) == S_IXGRP
)
412 if ( (perm
& (S_IXOTH
|S_ISVTX
)) == (S_IXOTH
|S_ISVTX
) )
414 else if ( (perm
& (S_IXOTH
|S_ISVTX
)) == S_ISVTX
)
416 else if ( (perm
& (S_IXOTH
|S_ISVTX
)) == S_IXOTH
)
421 // Include the type in the first char like kde3 did; people are more used to seeing it,
422 // even though it's not really part of the permissions per se.
425 else if (m_fileMode
!= KFileItem::Unknown
) {
426 if (S_ISDIR(m_fileMode
))
428 else if (S_ISSOCK(m_fileMode
))
430 else if (S_ISCHR(m_fileMode
))
432 else if (S_ISBLK(m_fileMode
))
434 else if (S_ISFIFO(m_fileMode
))
442 buffer
[1] = ((( perm
& S_IRUSR
) == S_IRUSR
) ? 'r' : '-' );
443 buffer
[2] = ((( perm
& S_IWUSR
) == S_IWUSR
) ? 'w' : '-' );
445 buffer
[4] = ((( perm
& S_IRGRP
) == S_IRGRP
) ? 'r' : '-' );
446 buffer
[5] = ((( perm
& S_IWGRP
) == S_IWGRP
) ? 'w' : '-' );
448 buffer
[7] = ((( perm
& S_IROTH
) == S_IROTH
) ? 'r' : '-' );
449 buffer
[8] = ((( perm
& S_IWOTH
) == S_IWOTH
) ? 'w' : '-' );
451 // if (hasExtendedACL())
452 if (m_entry
.contains(KIO::UDSEntry::UDS_EXTENDED_ACL
)) {
459 return QString::fromLatin1(buffer
);
465 KFileItem::KFileItem()
470 KFileItem::KFileItem( const KIO::UDSEntry
& entry
, const KUrl
& itemOrDirUrl
,
471 bool delayedMimeTypes
, bool urlIsDirectory
)
472 : d(new KFileItemPrivate(entry
, KFileItem::Unknown
, KFileItem::Unknown
,
473 itemOrDirUrl
, urlIsDirectory
, delayedMimeTypes
))
477 KFileItem::KFileItem( mode_t mode
, mode_t permissions
, const KUrl
& url
, bool delayedMimeTypes
)
478 : d(new KFileItemPrivate(KIO::UDSEntry(), mode
, permissions
,
479 url
, false, delayedMimeTypes
))
483 KFileItem::KFileItem( const KUrl
&url
, const QString
&mimeType
, mode_t mode
)
484 : d(new KFileItemPrivate(KIO::UDSEntry(), mode
, KFileItem::Unknown
,
487 d
->m_bMimeTypeKnown
= !mimeType
.isEmpty();
488 if (d
->m_bMimeTypeKnown
)
489 d
->m_pMimeType
= KMimeType::mimeType( mimeType
);
493 KFileItem::KFileItem(const KFileItem
& other
)
498 KFileItem::~KFileItem()
502 void KFileItem::refresh()
504 d
->m_fileMode
= KFileItem::Unknown
;
505 d
->m_permissions
= KFileItem::Unknown
;
506 d
->m_metaInfo
= KFileMetaInfo();
507 d
->m_hidden
= KFileItemPrivate::Auto
;
510 // Basically, we can't trust any information we got while listing.
511 // Everything could have changed...
512 // Clearing m_entry makes it possible to detect changes in the size of the file,
513 // the time information, etc.
518 void KFileItem::refreshMimeType()
521 d
->m_bMimeTypeKnown
= false;
522 d
->m_iconName
.clear();
525 void KFileItem::setUrl( const KUrl
&url
)
528 setName( url
.fileName() );
531 void KFileItem::setName( const QString
& name
)
534 d
->m_strText
= KIO::decodeFileName( d
->m_strName
);
537 QString
KFileItem::linkDest() const
539 // Extract it from the KIO::UDSEntry
540 const QString linkStr
= d
->m_entry
.stringValue( KIO::UDSEntry::UDS_LINK_DEST
);
541 if ( !linkStr
.isEmpty() )
544 // If not in the KIO::UDSEntry, or if UDSEntry empty, use readlink() [if local URL]
545 if ( d
->m_bIsLocalUrl
)
548 int n
= readlink( QFile::encodeName(d
->m_url
.toLocalFile( KUrl::RemoveTrailingSlash
)), buf
, sizeof(buf
)-1 );
552 return QFile::decodeName( buf
);
558 QString
KFileItem::localPath() const
560 if ( d
->m_bIsLocalUrl
) {
561 return d
->m_url
.toLocalFile();
564 // Extract the local path from the KIO::UDSEntry
565 return d
->m_entry
.stringValue( KIO::UDSEntry::UDS_LOCAL_PATH
);
568 KIO::filesize_t
KFileItem::size() const
573 bool KFileItem::hasExtendedACL() const
575 // Check if the field exists; its value doesn't matter
576 return d
->m_entry
.contains(KIO::UDSEntry::UDS_EXTENDED_ACL
);
579 KACL
KFileItem::ACL() const
581 if ( hasExtendedACL() ) {
582 // Extract it from the KIO::UDSEntry
583 const QString fieldVal
= d
->m_entry
.stringValue( KIO::UDSEntry::UDS_ACL_STRING
);
584 if ( !fieldVal
.isEmpty() )
585 return KACL( fieldVal
);
587 // create one from the basic permissions
588 return KACL( d
->m_permissions
);
591 KACL
KFileItem::defaultACL() const
593 // Extract it from the KIO::UDSEntry
594 const QString fieldVal
= d
->m_entry
.stringValue( KIO::UDSEntry::UDS_DEFAULT_ACL_STRING
);
595 if ( !fieldVal
.isEmpty() )
596 return KACL(fieldVal
);
601 KDateTime
KFileItem::time( FileTimes which
) const
603 return d
->time(which
);
606 time_t KFileItem::time( unsigned int which
) const
609 case KIO::UDSEntry::UDS_ACCESS_TIME
:
610 return d
->time(AccessTime
).toTime_t();
611 case KIO::UDSEntry::UDS_CREATION_TIME
:
612 return d
->time(CreationTime
).toTime_t();
613 case KIO::UDSEntry::UDS_MODIFICATION_TIME
:
615 return d
->time(ModificationTime
).toTime_t();
619 QString
KFileItem::user() const
624 QString
KFileItemPrivate::user() const
626 QString userName
= m_entry
.stringValue(KIO::UDSEntry::UDS_USER
);
627 if (userName
.isEmpty() && m_bIsLocalUrl
) {
629 QFileInfo
a(m_url
.toLocalFile( KUrl::RemoveTrailingSlash
));
630 userName
= a
.owner();
631 m_entry
.insert( KIO::UDSEntry::UDS_USER
, userName
);
633 KDE_struct_stat buff
;
634 if ( KDE::lstat( m_url
.toLocalFile( KUrl::RemoveTrailingSlash
), &buff
) == 0) // get uid/gid of the link, if it's a link
636 struct passwd
*pwuser
= getpwuid( buff
.st_uid
);
638 userName
= QString::fromLocal8Bit(pwuser
->pw_name
);
639 m_entry
.insert( KIO::UDSEntry::UDS_USER
, userName
);
647 QString
KFileItem::group() const
652 QString
KFileItemPrivate::group() const
654 QString groupName
= m_entry
.stringValue( KIO::UDSEntry::UDS_GROUP
);
655 if (groupName
.isEmpty() && m_bIsLocalUrl
)
658 QFileInfo
a(m_url
.toLocalFile( KUrl::RemoveTrailingSlash
));
659 groupName
= a
.group();
660 m_entry
.insert( KIO::UDSEntry::UDS_GROUP
, groupName
);
662 KDE_struct_stat buff
;
663 if ( KDE::lstat( m_url
.toLocalFile( KUrl::RemoveTrailingSlash
), &buff
) == 0) // get uid/gid of the link, if it's a link
665 struct group
*ge
= getgrgid( buff
.st_gid
);
667 groupName
= QString::fromLocal8Bit(ge
->gr_name
);
668 if (groupName
.isEmpty())
669 groupName
.sprintf("%d",ge
->gr_gid
);
672 groupName
.sprintf("%d",buff
.st_gid
);
673 m_entry
.insert( KIO::UDSEntry::UDS_GROUP
, groupName
);
680 QString
KFileItem::mimetype() const
682 KFileItem
* that
= const_cast<KFileItem
*>(this);
683 return that
->determineMimeType()->name();
686 KMimeType::Ptr
KFileItem::determineMimeType() const
688 if ( !d
->m_pMimeType
|| !d
->m_bMimeTypeKnown
)
691 KUrl url
= mostLocalUrl(isLocalUrl
);
693 d
->m_pMimeType
= KMimeType::findByUrl( url
, d
->m_fileMode
, isLocalUrl
);
694 Q_ASSERT(d
->m_pMimeType
);
695 //kDebug() << d << "finding final mimetype for" << url << ":" << d->m_pMimeType->name();
696 d
->m_bMimeTypeKnown
= true;
699 return d
->m_pMimeType
;
702 bool KFileItem::isMimeTypeKnown() const
704 // The mimetype isn't known if determineMimeType was never called (on-demand determination)
705 // or if this fileitem has a guessed mimetype (e.g. ftp symlink) - in which case
706 // it always remains "not fully determined"
707 return d
->m_bMimeTypeKnown
&& d
->m_guessedMimeType
.isEmpty();
710 QString
KFileItem::mimeComment() const
712 KMimeType::Ptr mType
= determineMimeType();
715 KUrl url
= mostLocalUrl(isLocalUrl
);
717 KMimeType::Ptr mime
= mimeTypePtr();
718 if (isLocalUrl
&& mime
->is("application/x-desktop")) {
719 KDesktopFile
cfg( url
.toLocalFile() );
720 QString comment
= cfg
.desktopGroup().readEntry( "Comment" );
721 if (!comment
.isEmpty())
725 QString comment
= mType
->comment( url
);
726 //kDebug() << "finding comment for " << url.url() << " : " << d->m_pMimeType->name();
727 if (!comment
.isEmpty())
730 return mType
->name();
733 static QString
iconFromDesktopFile(const QString
& path
)
735 KDesktopFile
cfg( path
);
736 const KConfigGroup group
= cfg
.desktopGroup();
737 const QString icon
= cfg
.readIcon();
738 const QString type
= cfg
.readPath();
740 if ( cfg
.hasDeviceType() )
742 const QString unmount_icon
= group
.readEntry( "UnmountIcon" );
743 const QString dev
= cfg
.readDevice();
744 if ( !icon
.isEmpty() && !unmount_icon
.isEmpty() && !dev
.isEmpty() )
746 KMountPoint::Ptr mountPoint
= KMountPoint::currentMountPoints().findByDevice(dev
);
747 if (!mountPoint
) // not mounted?
750 } else if ( cfg
.hasLinkType() ) {
751 const QString emptyIcon
= group
.readEntry( "EmptyIcon" );
752 if ( !emptyIcon
.isEmpty() ) {
753 const QString u
= cfg
.readUrl();
755 if ( url
.protocol() == "trash" ) {
756 // We need to find if the trash is empty, preferrably without using a KIO job.
757 // So instead kio_trash leaves an entry in its config file for us.
758 KConfig
trashConfig( "trashrc", KConfig::SimpleConfig
);
759 if ( trashConfig
.group("Status").readEntry( "Empty", true ) ) {
764 } else if ( group
.hasKey( "Exec" ) && !KDesktopFile::isAuthorizedDesktopFile( path
) ) {
765 // Disable custom icons for untrusted executables
766 return QString("application-x-desktop");
771 QString
KFileItem::iconName() const
773 if (d
->m_useIconNameCache
&& !d
->m_iconName
.isEmpty()) {
774 return d
->m_iconName
;
777 d
->m_iconName
= d
->m_entry
.stringValue( KIO::UDSEntry::UDS_ICON_NAME
);
778 if (!d
->m_iconName
.isEmpty()) {
779 d
->m_useIconNameCache
= d
->m_bMimeTypeKnown
;
780 return d
->m_iconName
;
784 KUrl url
= mostLocalUrl(isLocalUrl
);
786 KMimeType::Ptr mime
= mimeTypePtr();
787 if (isLocalUrl
&& mime
->is("application/x-desktop")) {
788 d
->m_iconName
= iconFromDesktopFile(url
.toLocalFile());
789 if (!d
->m_iconName
.isEmpty()) {
790 d
->m_useIconNameCache
= d
->m_bMimeTypeKnown
;
791 return d
->m_iconName
;
795 // KDE5: handle .directory files here too, and get rid of
796 // KFolderMimeType and the url argument in KMimeType::iconName().
798 d
->m_iconName
= mime
->iconName(url
);
799 d
->m_useIconNameCache
= d
->m_bMimeTypeKnown
;
800 //kDebug() << "finding icon for" << url << ":" << d->m_iconName;
801 return d
->m_iconName
;
804 QStringList
KFileItem::overlays() const
808 names
.append("emblem-symbolic-link");
811 if ( !S_ISDIR( d
->m_fileMode
) // Locked dirs have a special icon, use the overlay for files only
813 names
.append("object-locked");
817 names
.append("hidden");
821 if( S_ISDIR( d
->m_fileMode
) && d
->m_bIsLocalUrl
)
823 if (KSambaShare::instance()->isDirectoryShared( d
->m_url
.toLocalFile() ) ||
824 KNFSShare::instance()->isDirectoryShared( d
->m_url
.toLocalFile() ))
826 //kDebug() << d->m_url.path();
827 names
.append("network-workgroup");
832 if ( d
->m_pMimeType
&& d
->m_url
.fileName().endsWith( QLatin1String( ".gz" ) ) &&
833 d
->m_pMimeType
->is("application/x-gzip") ) {
834 names
.append("application-zip");
840 // ## where is this used?
841 QPixmap
KFileItem::pixmap( int _size
, int _state
) const
843 const QString iconName
= d
->m_entry
.stringValue( KIO::UDSEntry::UDS_ICON_NAME
);
844 if ( !iconName
.isEmpty() )
845 return DesktopIcon(iconName
, _size
, _state
);
847 if (!d
->m_pMimeType
) {
848 // No mimetype determined yet, go for a fast default icon
849 if (S_ISDIR(d
->m_fileMode
)) {
850 static const QString
* defaultFolderIcon
= 0;
851 if ( !defaultFolderIcon
) {
852 const KMimeType::Ptr mimeType
= KMimeType::mimeType( "inode/directory" );
854 defaultFolderIcon
= &KGlobal::staticQString( mimeType
->iconName() );
856 kWarning(7000) << "No mimetype for inode/directory could be found. Check your installation.";
858 if ( defaultFolderIcon
)
859 return DesktopIcon( *defaultFolderIcon
, _size
, _state
);
862 return DesktopIcon( "unknown", _size
, _state
);
866 // Use guessed mimetype if the main one hasn't been determined for sure
867 if ( !d
->m_bMimeTypeKnown
&& !d
->m_guessedMimeType
.isEmpty() )
868 mime
= KMimeType::mimeType( d
->m_guessedMimeType
);
870 mime
= d
->m_pMimeType
;
872 // Support for gzipped files: extract mimetype of contained file
873 // See also the relevant code in overlays, which adds the zip overlay.
874 if ( mime
->name() == "application/x-gzip" && d
->m_url
.fileName().endsWith( QLatin1String( ".gz" ) ) )
877 sf
.setPath( d
->m_url
.path().left( d
->m_url
.path().length() - 3 ) );
878 //kDebug() << "subFileName=" << subFileName;
879 mime
= KMimeType::findByUrl( sf
, 0, d
->m_bIsLocalUrl
);
883 KUrl url
= mostLocalUrl(isLocalUrl
);
885 QPixmap p
= KIconLoader::global()->loadMimeTypeIcon( mime
->iconName( url
), KIconLoader::Desktop
, _size
, _state
);
886 //kDebug() << "finding pixmap for " << url.url() << " : " << mime->name();
888 kWarning() << "Pixmap not found for mimetype " << d
->m_pMimeType
->name();
893 bool KFileItem::isReadable() const
896 struct passwd * user = getpwuid( geteuid() );
897 bool isMyFile = (QString::fromLocal8Bit(user->pw_name) == d->m_user);
898 // This gets ugly for the group....
899 // Maybe we want a static QString for the user and a static QStringList
900 // for the groups... then we need to handle the deletion properly...
903 if (d
->m_permissions
!= KFileItem::Unknown
) {
904 // No read permission at all
905 if ( !(S_IRUSR
& d
->m_permissions
) && !(S_IRGRP
& d
->m_permissions
) && !(S_IROTH
& d
->m_permissions
) )
908 // Read permissions for all: save a stat call
909 if ( (S_IRUSR
|S_IRGRP
|S_IROTH
) & d
->m_permissions
)
913 // Or if we can't read it [using ::access()] - not network transparent
914 if ( d
->m_bIsLocalUrl
&& KDE::access( d
->m_url
.toLocalFile(), R_OK
) == -1 )
920 bool KFileItem::isWritable() const
923 struct passwd * user = getpwuid( geteuid() );
924 bool isMyFile = (QString::fromLocal8Bit(user->pw_name) == d->m_user);
925 // This gets ugly for the group....
926 // Maybe we want a static QString for the user and a static QStringList
927 // for the groups... then we need to handle the deletion properly...
930 if (d
->m_permissions
!= KFileItem::Unknown
) {
931 // No write permission at all
932 if ( !(S_IWUSR
& d
->m_permissions
) && !(S_IWGRP
& d
->m_permissions
) && !(S_IWOTH
& d
->m_permissions
) )
936 // Or if we can't read it [using ::access()] - not network transparent
937 if ( d
->m_bIsLocalUrl
&& KDE::access( d
->m_url
.toLocalFile(), W_OK
) == -1 )
943 bool KFileItem::isHidden() const
945 // The kioslave can specify explicitly that a file is hidden or shown
946 if ( d
->m_hidden
!= KFileItemPrivate::Auto
)
947 return d
->m_hidden
== KFileItemPrivate::Hidden
;
949 // Prefer the filename that is part of the URL, in case the display name is different.
950 QString fileName
= d
->m_url
.fileName();
951 if (fileName
.isEmpty()) // e.g. "trash:/"
952 fileName
= d
->m_strName
;
953 return fileName
.length() > 1 && fileName
[0] == '.'; // Just "." is current directory, not hidden.
956 bool KFileItem::isDir() const
958 if (d
->m_fileMode
== KFileItem::Unknown
) {
959 // Probably the file was deleted already, and KDirLister hasn't told the world yet.
960 //kDebug() << d << url() << "can't say -> false";
961 return false; // can't say for sure, so no
963 return (S_ISDIR(d
->m_fileMode
));
966 bool KFileItem::isFile() const
971 bool KFileItem::acceptsDrops() const
974 if ( S_ISDIR( mode() ) ) {
978 // But only local .desktop files and executables
979 if ( !d
->m_bIsLocalUrl
)
982 if ( mimetype() == "application/x-desktop")
985 // Executable, shell script ... ?
986 if ( QFileInfo(d
->m_url
.toLocalFile()).isExecutable() )
992 QString
KFileItem::getStatusBarInfo() const
994 QString text
= d
->m_strText
;
995 const QString comment
= mimeComment();
1000 if ( comment
.isEmpty() )
1001 text
+= i18n ( "(Symbolic Link to %1)", linkDest() );
1003 text
+= i18n("(%1, Link to %2)", comment
, linkDest());
1005 else if ( targetUrl() != url() )
1007 text
+= i18n ( " (Points to %1)", targetUrl().pathOrUrl());
1009 else if ( S_ISREG( d
->m_fileMode
) )
1011 text
+= QString(" (%1, %2)").arg( comment
, KIO::convertSize( size() ) );
1015 text
+= QString(" (%1)").arg( comment
);
1020 QString
KFileItem::getToolTipText(int maxcount
) const
1022 // we can return QString() if no tool tip should be shown
1024 KFileMetaInfo info
= metaInfo();
1026 // the font tags are a workaround for the fact that the tool tip gets
1027 // screwed if the color scheme uses white as default text color
1028 const QString colorName
= QApplication::palette().color(QPalette::ToolTipText
).name();
1029 const QString start
= "<tr><td align=\"right\"><nobr><font color=\"" + colorName
+ "\"><b>";
1030 const QString mid
= " </b></font></nobr></td><td><nobr><font color=\"" + colorName
+ "\">";
1031 const char* end
= "</font></nobr></td></tr>";
1033 tip
= "<table cellspacing=0 cellpadding=0>";
1035 tip
+= start
+ i18n("Name:") + mid
+ text() + end
;
1036 tip
+= start
+ i18n("Type:") + mid
;
1038 QString type
= Qt::escape(mimeComment());
1040 tip
+= i18n("Link to %1 (%2)", linkDest(), type
) + end
;
1044 if ( !S_ISDIR ( d
->m_fileMode
) )
1045 tip
+= start
+ i18n("Size:") + mid
+
1046 QString("%1").arg(KIO::convertSize(size())) +
1049 tip
+= start
+ i18n("Modified:") + mid
+
1050 timeString( KFileItem::ModificationTime
) + end
1051 #ifndef Q_WS_WIN //TODO: show win32-specific permissions
1052 +start
+ i18n("Owner:") + mid
+ user() + " - " + group() + end
+
1053 start
+ i18n("Permissions:") + mid
+
1054 permissionsString() + end
1060 const QStringList keys
= info
.preferredKeys();
1063 QStringList::ConstIterator it
= keys
.begin();
1064 for (int count
= 0; count
<maxcount
&& it
!=keys
.end() ; ++it
)
1068 tip
+= "<tr><td colspan=2><center><s> </s></center></td></tr>";
1071 KFileMetaInfoItem item
= info
.item( *it
);
1072 if ( item
.isValid() )
1074 QString s
= item
.value().toString();
1075 if ( ( item
.properties().attributes() & PredicateProperties::SqueezeText
)
1076 && s
.length() > 50) {
1084 Qt::escape( item
.name() ) + ':' +
1095 //kDebug() << "making this the tool tip rich text:\n";
1101 void KFileItem::run( QWidget
* parentWidget
) const
1103 (void) new KRun( targetUrl(), parentWidget
, d
->m_fileMode
, d
->m_bIsLocalUrl
);
1106 bool KFileItem::cmp( const KFileItem
& item
) const
1108 return d
->cmp(*item
.d
);
1111 bool KFileItem::operator==(const KFileItem
& other
) const
1114 return d
== other
.d
;
1117 bool KFileItem::operator!=(const KFileItem
& other
) const
1119 return d
!= other
.d
;
1122 void KFileItem::setUDSEntry( const KIO::UDSEntry
& _entry
, const KUrl
& _url
,
1123 bool _delayedMimeTypes
, bool _urlIsDirectory
)
1125 d
->m_entry
= _entry
;
1127 d
->m_strName
.clear();
1128 d
->m_strText
.clear();
1129 d
->m_iconName
.clear();
1130 d
->m_strLowerCaseName
.clear();
1132 d
->m_fileMode
= KFileItem::Unknown
;
1133 d
->m_permissions
= KFileItem::Unknown
;
1134 d
->m_bMarked
= false;
1136 d
->m_bIsLocalUrl
= _url
.isLocalFile();
1137 d
->m_bMimeTypeKnown
= false;
1138 d
->m_hidden
= KFileItemPrivate::Auto
;
1139 d
->m_guessedMimeType
.clear();
1140 d
->m_metaInfo
= KFileMetaInfo();
1141 d
->m_delayedMimeTypes
= _delayedMimeTypes
;
1142 d
->m_useIconNameCache
= false;
1144 d
->readUDSEntry( _urlIsDirectory
);
1148 KFileItem::operator QVariant() const
1150 return qVariantFromValue(*this);
1153 void KFileItem::setExtraData( const void *key
, void *value
)
1158 d
->m_extra
.insert( key
, value
); // replaces the value of key if already there
1161 const void * KFileItem::extraData( const void *key
) const
1163 return d
->m_extra
.value( key
, 0 );
1166 void KFileItem::removeExtraData( const void *key
)
1168 d
->m_extra
.remove( key
);
1171 QString
KFileItem::permissionsString() const
1173 if (d
->m_access
.isNull() && d
->m_permissions
!= KFileItem::Unknown
)
1174 d
->m_access
= d
->parsePermissions( d
->m_permissions
);
1179 // check if we need to cache this
1180 QString
KFileItem::timeString( FileTimes which
) const
1182 return KGlobal::locale()->formatDateTime( d
->time(which
) );
1185 QString
KFileItem::timeString( unsigned int which
) const
1188 case KIO::UDSEntry::UDS_ACCESS_TIME
:
1189 return timeString(AccessTime
);
1190 case KIO::UDSEntry::UDS_CREATION_TIME
:
1191 return timeString(CreationTime
);
1192 case KIO::UDSEntry::UDS_MODIFICATION_TIME
:
1194 return timeString(ModificationTime
);
1198 void KFileItem::setMetaInfo( const KFileMetaInfo
& info
) const
1200 d
->m_metaInfo
= info
;
1203 KFileMetaInfo
KFileItem::metaInfo(bool autoget
, int) const
1205 if (autoget
&& !d
->m_metaInfo
.isValid())
1208 KUrl
url(mostLocalUrl(isLocalUrl
));
1209 if (KGlobalSettings::showFilePreview(url
))
1210 d
->m_metaInfo
= KFileMetaInfo(url
);//, mimetype() );
1212 return d
->m_metaInfo
;
1215 void KFileItem::assign( const KFileItem
& item
)
1220 KUrl
KFileItem::mostLocalUrl(bool &local
) const
1222 QString local_path
= localPath();
1224 if ( !local_path
.isEmpty() )
1228 url
.setPath(local_path
);
1233 local
= d
->m_bIsLocalUrl
;
1238 QDataStream
& operator<< ( QDataStream
& s
, const KFileItem
& a
)
1240 // We don't need to save/restore anything that refresh() invalidates,
1241 // since that means we can re-determine those by ourselves.
1243 s
<< a
.d
->m_strName
;
1244 s
<< a
.d
->m_strText
;
1248 QDataStream
& operator>> ( QDataStream
& s
, KFileItem
& a
)
1251 s
>> a
.d
->m_strName
;
1252 s
>> a
.d
->m_strText
;
1253 a
.d
->m_bIsLocalUrl
= a
.d
->m_url
.isLocalFile();
1254 a
.d
->m_bMimeTypeKnown
= false;
1259 KUrl
KFileItem::url() const
1264 mode_t
KFileItem::permissions() const
1266 return d
->m_permissions
;
1269 mode_t
KFileItem::mode() const
1271 return d
->m_fileMode
;
1274 bool KFileItem::isLink() const
1279 bool KFileItem::isLocalFile() const
1281 return d
->m_bIsLocalUrl
;
1284 QString
KFileItem::text() const
1286 return d
->m_strText
;
1289 QString
KFileItem::name( bool lowerCase
) const
1292 return d
->m_strName
;
1294 if ( d
->m_strLowerCaseName
.isNull() )
1295 d
->m_strLowerCaseName
= d
->m_strName
.toLower();
1296 return d
->m_strLowerCaseName
;
1299 KUrl
KFileItem::targetUrl() const
1301 const QString targetUrlStr
= d
->m_entry
.stringValue( KIO::UDSEntry::UDS_TARGET_URL
);
1302 if (!targetUrlStr
.isEmpty())
1303 return KUrl(targetUrlStr
);
1309 * Mimetype handling.
1311 * Initial state: m_pMimeType = 0.
1312 * When mimeTypePtr() is called first: fast mimetype determination,
1313 * might either find an accurate mimetype (-> Final state), otherwise we
1314 * set m_pMimeType but not m_bMimeTypeKnown (-> Intermediate state)
1315 * Intermediate state: determineMimeType() does the real determination -> Final state.
1317 * If delayedMimeTypes isn't set, then we always go to the Final state directly.
1320 KMimeType::Ptr
KFileItem::mimeTypePtr() const
1322 if (!d
->m_pMimeType
) {
1323 // On-demand fast (but not always accurate) mimetype determination
1324 Q_ASSERT(!d
->m_url
.isEmpty());
1326 KUrl url
= mostLocalUrl(isLocalUrl
);
1328 d
->m_pMimeType
= KMimeType::findByUrl( url
, d
->m_fileMode
, isLocalUrl
,
1329 // use fast mode if delayed mimetype determination can refine it later
1330 d
->m_delayedMimeTypes
, &accuracy
);
1331 // If we used the "fast mode" (no sniffing), and we didn't get a perfect (extension-based) match,
1332 // then determineMimeType will be able to do better.
1333 const bool canDoBetter
= d
->m_delayedMimeTypes
&& accuracy
< 100;
1334 //kDebug() << "finding mimetype for" << url << ":" << d->m_pMimeType->name() << "canDoBetter=" << canDoBetter;
1335 d
->m_bMimeTypeKnown
= !canDoBetter
;
1337 return d
->m_pMimeType
;
1340 KIO::UDSEntry
KFileItem::entry() const
1345 bool KFileItem::isMarked() const
1347 return d
->m_bMarked
;
1350 void KFileItem::mark()
1352 d
->m_bMarked
= true;
1355 void KFileItem::unmark()
1357 d
->m_bMarked
= false;
1360 KFileItem
& KFileItem::operator=(const KFileItem
& other
)
1366 bool KFileItem::isNull() const
1371 KFileItemList::KFileItemList()
1375 KFileItemList::KFileItemList( const QList
<KFileItem
> &items
)
1376 : QList
<KFileItem
>( items
)
1380 KFileItem
KFileItemList::findByName( const QString
& fileName
) const
1382 const_iterator it
= begin();
1383 const const_iterator itend
= end();
1384 for ( ; it
!= itend
; ++it
) {
1385 if ( (*it
).name() == fileName
) {
1392 KFileItem
KFileItemList::findByUrl( const KUrl
& url
) const {
1393 const_iterator it
= begin();
1394 const const_iterator itend
= end();
1395 for ( ; it
!= itend
; ++it
) {
1396 if ( (*it
).url() == url
) {
1403 KUrl::List
KFileItemList::urlList() const {
1405 const_iterator it
= begin();
1406 const const_iterator itend
= end();
1407 for ( ; it
!= itend
; ++it
) {
1408 lst
.append( (*it
).url() );
1413 KUrl::List
KFileItemList::targetUrlList() const {
1415 const_iterator it
= begin();
1416 const const_iterator itend
= end();
1417 for ( ; it
!= itend
; ++it
) {
1418 lst
.append( (*it
).targetUrl() );
1423 bool KFileItem::isDesktopFile() const
1427 const KUrl url
= mostLocalUrl(isLocal
);
1431 // only regular files
1432 if (!S_ISREG(d
->m_fileMode
))
1439 // return true if desktop file
1440 return determineMimeType()->is("application/x-desktop");