• Skip to content
  • Skip to link menu
KDE 4.3 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KDECore

kmimetype.cpp

Go to the documentation of this file.
00001 /*  This file is part of the KDE libraries
00002  *  Copyright (C) 1999 Waldo Bastian <bastian@kde.org>
00003  *                2000-2007 David Faure <faure@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 version 2 as published by the Free Software Foundation;
00008  *
00009  *  This library is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  *  Library General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU Library General Public License
00015  *  along with this library; see the file COPYING.LIB.  If not, write to
00016  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  *  Boston, MA 02110-1301, USA.
00018  **/
00019 
00020 #include "kmimetype.h"
00021 #include "kmimetype_p.h"
00022 #include "kmimetypefactory.h"
00023 
00024 #include <kconfig.h>
00025 #include <kconfiggroup.h>
00026 #include <kdebug.h>
00027 #include <kde_file.h>
00028 #include <kdeversion.h>
00029 #include <klocale.h>
00030 #include <kmessage.h>
00031 #include <kprotocolinfo.h>
00032 #include <kprotocolinfofactory.h>
00033 #include <kstandarddirs.h>
00034 #include <ksycoca.h>
00035 #include <kurl.h>
00036 
00037 #include <QtCore/QFile>
00038 #include <QtDBus/QtDBus>
00039 #include <QBuffer>
00040 
00041 #include <sys/types.h>
00042 #include <sys/stat.h>
00043 
00044 #include <assert.h>
00045 #include <errno.h>
00046 #include <stddef.h>
00047 #include <unistd.h>
00048 #include <stdlib.h>
00049 
00050 template class KSharedPtr<KMimeType>;
00051 
00052 static KMimeType::Ptr s_pDefaultMimeType;
00053 
00054 static void errorMissingMimeTypes( const QStringList& _types )
00055 {
00056     KMessage::message( KMessage::Error, i18np( "Could not find mime type <resource>%2</resource>",
00057                 "Could not find mime types:\n<resource>%2</resource>", _types.count(), _types.join("</resource>\n<resource>") ) );
00058 }
00059 
00060 void KMimeTypePrivate::loadInternal( QDataStream& _str )
00061 {
00062     QString oldParentMimeTypeString;
00063     QStringList oldParentMimeTypesList;
00064     _str >> m_lstPatterns >> oldParentMimeTypeString >> oldParentMimeTypesList >> m_iconName;
00065 }
00066 
00071 void KMimeType::buildDefaultType()
00072 {
00073     assert ( !s_pDefaultMimeType );
00074     // Try to find the default type
00075     KMimeType::Ptr mime = KMimeTypeFactory::self()->
00076                           findMimeTypeByName( KMimeType::defaultMimeType() );
00077 
00078     if (mime)
00079     {
00080         s_pDefaultMimeType = mime;
00081     }
00082     else
00083     {
00084         QString defaultMimeType = KMimeType::defaultMimeType();
00085         errorMissingMimeTypes( QStringList(defaultMimeType) );
00086         QString sDefaultMimeType = KGlobal::dirs()->resourceDirs("xdgdata-mime").first()+defaultMimeType+".xml";
00087         s_pDefaultMimeType = new KMimeType( sDefaultMimeType, defaultMimeType, "mime" );
00088     }
00089 }
00090 
00091 KMimeType::Ptr KMimeType::defaultMimeTypePtr()
00092 {
00093     if ( !s_pDefaultMimeType ) // we need a default type first
00094         buildDefaultType();
00095     return s_pDefaultMimeType;
00096 }
00097 
00098 bool KMimeType::isDefault() const
00099 {
00100     return name() == defaultMimeType();
00101 }
00102 
00106 void KMimeType::checkEssentialMimeTypes()
00107 {
00108     static bool s_bChecked = false;
00109 
00110     if ( s_bChecked ) // already done
00111         return;
00112     if ( !s_pDefaultMimeType ) // we need a default type first
00113         KMimeType::buildDefaultType();
00114 
00115   s_bChecked = true; // must be done before building mimetypes
00116 
00117   // No Mime-Types installed ?
00118   // Lets do some rescue here.
00119   if ( !KMimeTypeFactory::self()->checkMimeTypes() )
00120   {
00121     // Note that this messagebox is queued, so it will only be shown once getting back to the event loop
00122 
00123     // No mimetypes installed? Are you setting XDG_DATA_DIRS without including /usr/share in it?
00124     KMessage::message( KMessage::Error, i18n( "No mime types installed. Check that shared-mime-info is installed, and that XDG_DATA_DIRS is not set, or includes /usr/share." ) );
00125     return; // no point in going any further
00126   }
00127 
00128   QStringList missingMimeTypes;
00129 
00130 #ifndef Q_OS_WIN
00131   if ( !KMimeType::mimeType( "inode/directory" ) )
00132     missingMimeTypes.append( "inode/directory" );
00133   //if ( !KMimeType::mimeType( "inode/directory-locked" ) )
00134   //  missingMimeTypes.append( "inode/directory-locked" );
00135   if ( !KMimeType::mimeType( "inode/blockdevice" ) )
00136     missingMimeTypes.append( "inode/blockdevice" );
00137   if ( !KMimeType::mimeType( "inode/chardevice" ) )
00138     missingMimeTypes.append( "inode/chardevice" );
00139   if ( !KMimeType::mimeType( "inode/socket" ) )
00140     missingMimeTypes.append( "inode/socket" );
00141   if ( !KMimeType::mimeType( "inode/fifo" ) )
00142     missingMimeTypes.append( "inode/fifo" );
00143 #endif
00144   if ( !KMimeType::mimeType( "application/x-shellscript" ) )
00145     missingMimeTypes.append( "application/x-shellscript" );
00146   if ( !KMimeType::mimeType( "application/x-executable" ) )
00147     missingMimeTypes.append( "application/x-executable" );
00148   if ( !KMimeType::mimeType( "application/x-desktop" ) )
00149     missingMimeTypes.append( "application/x-desktop" );
00150 
00151   if (!missingMimeTypes.isEmpty())
00152     errorMissingMimeTypes(missingMimeTypes);
00153 }
00154 
00155 KMimeType::Ptr KMimeType::mimeType( const QString& _name, FindByNameOption options )
00156 {
00157     return KMimeTypeFactory::self()->findMimeTypeByName( _name, options );
00158 }
00159 
00160 KMimeType::List KMimeType::allMimeTypes()
00161 {
00162     return KMimeTypeFactory::self()->allMimeTypes();
00163 }
00164 
00165 bool KMimeType::isBufferBinaryData(const QByteArray& data)
00166 {
00167     // Check the first 32 bytes (see shared-mime spec)
00168     const char* p = data.data();
00169     const int end = qMin(32, data.size());
00170     for (int i = 0; i < end; ++i) {
00171         if ((unsigned char)(p[i]) < 32 && p[i] != 9 && p[i] != 10 && p[i] != 13) // ASCII control character
00172             return true;
00173     }
00174     return false;
00175 }
00176 
00177 static KMimeType::Ptr findFromMode( const QString& path /*only used if is_local_file*/,
00178                                     mode_t mode /*0 if unknown*/,
00179                                     bool is_local_file )
00180 {
00181     if ( is_local_file && (mode == 0 || mode == (mode_t)-1) ) {
00182         KDE_struct_stat buff;
00183         if ( KDE::stat( path, &buff ) != -1 )
00184             mode = buff.st_mode;
00185     }
00186 
00187     if ( S_ISDIR( mode ) ) {
00188         // KDE4 TODO: use an overlay instead
00189 #if 0
00190         // Special hack for local files. We want to see whether we
00191         // are allowed to enter the directory
00192         if ( is_local_file )
00193         {
00194             if ( KDE::access( path, R_OK ) == -1 )
00195                 return KMimeType::mimeType( "inode/directory-locked" );
00196         }
00197 #endif
00198         return KMimeType::mimeType( "inode/directory" );
00199     }
00200     if ( S_ISCHR( mode ) )
00201         return KMimeType::mimeType( "inode/chardevice" );
00202     if ( S_ISBLK( mode ) )
00203         return KMimeType::mimeType( "inode/blockdevice" );
00204     if ( S_ISFIFO( mode ) )
00205         return KMimeType::mimeType( "inode/fifo" );
00206     if ( S_ISSOCK( mode ) )
00207         return KMimeType::mimeType( "inode/socket" );
00208 #ifdef Q_OS_WIN
00209     // FIXME: distinguish between mounted & unmounted
00210     int size = path.size();
00211     if ( size == 2 || size == 3 ) {
00212         unsigned int type = GetDriveTypeW( (LPCWSTR) path.utf16() );
00213         switch( type ) {
00214             case DRIVE_REMOVABLE:
00215                 return KMimeType::mimeType( "media/floppy_mounted" );
00216             case DRIVE_FIXED:
00217                 return KMimeType::mimeType( "media/hdd_mounted" );
00218             case DRIVE_REMOTE:
00219                 return KMimeType::mimeType( "media/smb_mounted" );
00220             case DRIVE_CDROM:
00221                 return KMimeType::mimeType( "media/cdrom_mounted" );
00222             case DRIVE_RAMDISK:
00223                 return KMimeType::mimeType( "media/hdd_mounted" );
00224             default:
00225                 break;
00226         };
00227     }
00228 #endif
00229     // remote executable file? stop here (otherwise findFromContent can do that better for local files)
00230     if ( !is_local_file && S_ISREG( mode ) && ( mode & ( S_IXUSR | S_IXGRP | S_IXOTH ) ) )
00231         return KMimeType::mimeType( "application/x-executable" );
00232 
00233     return KMimeType::Ptr();
00234 }
00235 
00236 static bool mimeTypeListSortByName(const KMimeType::Ptr& m1, const KMimeType::Ptr& m2)
00237 {
00238     return m1->name() < m2->name();
00239 }
00240 
00241 /*
00242 
00243 As agreed on the XDG list (and unlike the current shared-mime spec):
00244 
00245 Glob-matching should prefer derived mimetype over base mimetype, and longer matches
00246 over shorter ones. However if two globs of the same length match the file, and the two
00247 matches are not related in the inheritance tree, then we have a "glob conflict", which
00248 will be resolved below.
00249 
00250 If only one glob matches, use that
00251 
00252 If no glob matches, sniff and use that
00253 
00254 If several globs matches, and sniffing gives a result we do:
00255   if sniffed prio >= 80, use sniffed type
00256   for glob_match in glob_matches:
00257      if glob_match is subclass or equal to sniffed_type, use glob_match
00258 
00259 If several globs matches, and sniffing fails, or doesn't help:
00260   fall back to the first glob match
00261 
00262 This algorithm only sniffs when there is some uncertainty with the
00263 extension matching (thus, it's usable for a file manager).
00264 
00265 Note: in KDE we want the file views to sniff in a delayed manner.
00266 So there's also a fast mode which is:
00267  if no glob matches, or if more than one glob matches, use default mimetype and mark as "can be refined".
00268 
00269 */
00270 
00271 KMimeType::Ptr KMimeType::findByUrlHelper( const KUrl& _url, mode_t mode,
00272                                            bool is_local_file,
00273                                            QIODevice* device,
00274                                            int* accuracy )
00275 {
00276     checkEssentialMimeTypes();
00277     const QString path = is_local_file ? _url.toLocalFile() : _url.path();
00278 
00279     if (accuracy)
00280         *accuracy = 100;
00281 
00282     // Look at mode first
00283     KMimeType::Ptr mimeFromMode = findFromMode( path, mode, is_local_file );
00284     if (mimeFromMode)
00285         return mimeFromMode;
00286 
00287     // First try to find out by looking at the filename (if there's one)
00288     const QString fileName( _url.fileName() );
00289     QList<KMimeType::Ptr> mimeList;
00290     if ( !fileName.isEmpty() && !path.endsWith( '/' ) ) {
00291         // and if we can trust it (e.g. don't trust *.pl over HTTP, could be anything)
00292         if ( is_local_file || _url.hasSubUrl() || // Explicitly trust suburls
00293              KProtocolInfo::determineMimetypeFromExtension( _url.protocol() ) ) {
00294             mimeList = KMimeTypeFactory::self()->findFromFileName( fileName );
00295             // Found one glob match exactly: OK, use that.
00296             // We disambiguate multiple glob matches by sniffing, below.
00297             if ( mimeList.count() == 1 ) {
00298                 return mimeList.first();
00299             }
00300         }
00301     }
00302 
00303     if ( device && !device->isOpen() ) {
00304         if ( !device->open(QIODevice::ReadOnly) ) {
00305             device = 0;
00306         }
00307     }
00308 
00309     // Try the magic matches (if we can read the data)
00310     QByteArray beginning;
00311     if ( device ) {
00312         int magicAccuracy;
00313         KMimeType::Ptr mime = KMimeTypeFactory::self()->findFromContent(
00314             device, KMimeTypeFactory::AllRules, &magicAccuracy, beginning );
00315         // mime can't be 0, except in case of install problems.
00316         // However we get magicAccuracy==0 for octet-stream, i.e. no magic match found.
00317         //kDebug(7009) << "findFromContent said" << (mime?mime->name():QString()) << "with accuracy" << magicAccuracy;
00318         if (mime && magicAccuracy > 0) {
00319 
00320             // Disambiguate conflicting extensions (if magic found something and the magicrule was <80)
00321             if (magicAccuracy < 80 && !mimeList.isEmpty()) {
00322                 // "for glob_match in glob_matches:"
00323                 // "if glob_match is subclass or equal to sniffed_type, use glob_match"
00324                 const QString sniffedMime = mime->name();
00325                 foreach(const KMimeType::Ptr &mimeFromPattern, mimeList) {
00326                     //kDebug(7009) << "sniffedMime=" << sniffedMime << "mimeFromPattern=" << mimeFromPattern->name();
00327                     if (mimeFromPattern->is(sniffedMime)) {
00328                         // We have magic + pattern pointing to this, so it's a pretty good match
00329                         if (accuracy)
00330                             *accuracy = 100;
00331                         return mimeFromPattern;
00332                     }
00333                 }
00334             }
00335 
00336             if (accuracy)
00337                 *accuracy = magicAccuracy;
00338             return mime;
00339         }
00340     }
00341 
00342     // Not a local file, or no magic allowed, or magic found nothing
00343 
00344     // Maybe we had multiple matches from globs?
00345     if (!mimeList.isEmpty()) {
00346         if (accuracy)
00347             *accuracy = 20;
00348         // We have to pick one...
00349         // At least make this deterministic
00350         qSort(mimeList.begin(), mimeList.end(), mimeTypeListSortByName);
00351         return mimeList.first();
00352     }
00353 
00354     // Find a fallback from the protocol
00355     if (accuracy)
00356         *accuracy = 10;
00357     // ## this breaks with proxying; find a way to move proxying info to kdecore's kprotocolinfo?
00358     // ## or hardcode the only case of proxying that we ever had? (ftp-over-http)
00359     KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol( _url.protocol() );
00360     QString def;
00361     if (prot)
00362         def = prot->defaultMimeType();
00363     if ( !def.isEmpty() && def != defaultMimeType() ) {
00364         // The protocol says it always returns a given mimetype (e.g. text/html for "man:")
00365         KMimeType::Ptr mime = mimeType( def );
00366         if (mime)
00367             return mime;
00368     }
00369     if ( path.endsWith( '/' ) || path.isEmpty() ) {
00370         // We have no filename at all. Maybe the protocol has a setting for
00371         // which mimetype this means (e.g. directory).
00372         // For HTTP (def==defaultMimeType()) we don't assume anything,
00373         // because of redirections (e.g. freshmeat downloads).
00374         if ( def.isEmpty() ) {
00375             // Assume inode/directory, if the protocol supports listing.
00376             KProtocolInfo::Ptr prot = KProtocolInfoFactory::self()->findProtocol( _url.protocol() );
00377             if ( prot && prot->supportsListing() ) {
00378                 KMimeType::Ptr mime = mimeType( QLatin1String("inode/directory") );
00379                 if (mime) { // only 0 if no mimetypes installed
00380                     return mime;
00381                 }
00382             } else
00383                 return defaultMimeTypePtr(); // == 'no idea', e.g. for "data:,foo/"
00384         }
00385     }
00386 
00387     if (accuracy)
00388         *accuracy = 0;
00389     return defaultMimeTypePtr();
00390 }
00391 
00392 KMimeType::Ptr KMimeType::findByUrl( const KUrl& url, mode_t mode,
00393                                      bool is_local_file, bool fast_mode,
00394                                      int *accuracy )
00395 {
00396     if ( !is_local_file && url.isLocalFile() )
00397         is_local_file = true;
00398     if (is_local_file && !fast_mode) {
00399         QFile file(url.toLocalFile());
00400         return findByUrlHelper(url, mode, is_local_file, &file, accuracy);
00401     }
00402     return findByUrlHelper(url, mode, is_local_file, 0, accuracy);
00403 }
00404 
00405 KMimeType::Ptr KMimeType::findByPath( const QString& path, mode_t mode,
00406                                       bool fast_mode, int* accuracy )
00407 {
00408     KUrl url;
00409     url.setPath(path);
00410     return findByUrl(url, mode, true, fast_mode, accuracy);
00411 }
00412 
00413 KMimeType::Ptr KMimeType::findByNameAndContent( const QString& name, const QByteArray& data,
00414                                                 mode_t mode, int* accuracy )
00415 {
00416     KUrl url;
00417     url.setPath(name);
00418     QBuffer buffer(const_cast<QByteArray *>(&data));
00419     return findByUrlHelper(url, mode, false, &buffer, accuracy);
00420 }
00421 
00422 QString KMimeType::extractKnownExtension(const QString &fileName)
00423 {
00424     QString pattern;
00425     KMimeTypeFactory::self()->findFromFileName( fileName, &pattern );
00426     return pattern;
00427 }
00428 
00429 KMimeType::Ptr KMimeType::findByContent( const QByteArray &data, int *accuracy )
00430 {
00431     QBuffer buffer(const_cast<QByteArray *>(&data));
00432     buffer.open(QIODevice::ReadOnly);
00433     QByteArray cache;
00434     return KMimeTypeFactory::self()->findFromContent(
00435         &buffer, KMimeTypeFactory::AllRules, accuracy, cache );
00436 }
00437 
00438 KMimeType::Ptr KMimeType::findByFileContent( const QString &fileName, int *accuracy )
00439 {
00440     checkEssentialMimeTypes();
00441 
00442     QFile device(fileName);
00443     // Look at mode first
00444     KMimeType::Ptr mimeFromMode = findFromMode( fileName, 0, true );
00445     if (mimeFromMode) {
00446         if (accuracy)
00447             *accuracy = 100;
00448         return mimeFromMode;
00449     }
00450     if (!device.open(QIODevice::ReadOnly)) {
00451         if (accuracy)
00452             *accuracy = 0;
00453         return KMimeType::defaultMimeTypePtr();
00454     }
00455 
00456     QByteArray cache;
00457     return KMimeTypeFactory::self()->findFromContent(
00458         &device, KMimeTypeFactory::AllRules, accuracy, cache );
00459 }
00460 
00461 bool KMimeType::isBinaryData( const QString &fileName )
00462 {
00463     QFile file(fileName);
00464     if (!file.open(QIODevice::ReadOnly))
00465         return false; // err, whatever
00466     const QByteArray data = file.read(32);
00467     return isBufferBinaryData(data);
00468 }
00469 
00470 KMimeType::KMimeType( KMimeTypePrivate &dd, const QString& name,
00471                       const QString& comment )
00472     : KServiceType( dd, name, comment )
00473 {
00474 }
00475 
00476 KMimeType::KMimeType( const QString & fullpath, const QString& name,
00477                       const QString& comment )
00478     : KServiceType( *new KMimeTypePrivate(fullpath), name, comment )
00479 {
00480 }
00481 
00482 KMimeType::KMimeType( KMimeTypePrivate &dd)
00483     : KServiceType(dd)
00484 {
00485 }
00486 
00487 KMimeType::KMimeType( QDataStream& _str, int offset )
00488     : KServiceType( *new KMimeTypePrivate(_str, offset ))
00489 {
00490 }
00491 
00492 void KMimeTypePrivate::save( QDataStream& _str )
00493 {
00494     KServiceTypePrivate::save( _str );
00495     // Warning adding fields here involves a binary incompatible change - update version
00496     // number in ksycoca.h. Never remove fields.
00497     _str << m_lstPatterns << QString() << QStringList() << m_iconName;
00498 }
00499 
00500 QVariant KMimeTypePrivate::property( const QString& _name ) const
00501 {
00502     if ( _name == "Patterns" )
00503         return QVariant( m_lstPatterns );
00504     if ( _name == "Icon" )
00505         return QVariant( iconName(KUrl()) );
00506 
00507     return KServiceTypePrivate::property( _name );
00508 }
00509 
00510 QStringList KMimeTypePrivate::propertyNames() const
00511 {
00512     QStringList res = KServiceTypePrivate::propertyNames();
00513     res.append( "Patterns" );
00514     res.append( "Icon" );
00515     return res;
00516 }
00517 
00518 KMimeType::~KMimeType()
00519 {
00520 }
00521 
00522 QString KMimeType::iconNameForUrl( const KUrl & _url, mode_t mode )
00523 {
00524     const KMimeType::Ptr mt = findByUrl( _url, mode, _url.isLocalFile(),
00525                                          false /*HACK*/);
00526     if (!mt) {
00527         return QString();
00528     }
00529     static const QString& unknown = KGlobal::staticQString("unknown");
00530     const QString mimeTypeIcon = mt->iconName( _url );
00531     QString i = mimeTypeIcon;
00532 
00533     // if we don't find an icon, maybe we can use the one for the protocol
00534     if ( i == unknown || i.isEmpty() || mt->name() == defaultMimeType()
00535         // and for the root of the protocol (e.g. trash:/) the protocol icon has priority over the mimetype icon
00536         || _url.path().length() <= 1 )
00537     {
00538         i = favIconForUrl( _url ); // maybe there is a favicon?
00539 
00540         if ( i.isEmpty() )
00541             i = KProtocolInfo::icon( _url.protocol() );
00542 
00543         // root of protocol: if we found nothing, revert to mimeTypeIcon (which is usually "folder")
00544         if ( _url.path().length() <= 1 && ( i == unknown || i.isEmpty() ) )
00545             i = mimeTypeIcon;
00546     }
00547     return !i.isEmpty() ? i : unknown;
00548 }
00549 
00550 QString KMimeType::favIconForUrl( const KUrl& url )
00551 {
00552     // this method will be called quite often, so better not read the config
00553     // again and again.
00554     static bool useFavIcons = true;
00555     static bool check = true;
00556     if ( check ) {
00557         check = false;
00558         KConfigGroup cg( KGlobal::config(), "HTML Settings" );
00559         useFavIcons = cg.readEntry("EnableFavicon", true);
00560     }
00561 
00562     if ( url.isLocalFile() || !url.protocol().startsWith("http")
00563          || !useFavIcons )
00564         return QString();
00565 
00566     QDBusInterface kded( "org.kde.kded", "/modules/favicons", "org.kde.FavIcon" );
00567     QDBusReply<QString> result = kded.call( "iconForUrl", url.url() );
00568     return result;              // default is QString()
00569 }
00570 
00571 QString KMimeType::comment( const KUrl &url) const
00572 {
00573     Q_D(const KMimeType);
00574     return d->comment(url);
00575 }
00576 
00577 static QString fallbackParent(const QString& mimeTypeName)
00578 {
00579     const QString myGroup = mimeTypeName.left(mimeTypeName.indexOf('/'));
00580     // All text/* types are subclasses of text/plain.
00581     if (myGroup == "text" && mimeTypeName != "text/plain")
00582         return "text/plain";
00583     // All real-file mimetypes implicitly derive from application/octet-stream
00584     if (myGroup != "inode" &&
00585         // kde extensions
00586         myGroup != "all" && myGroup != "fonts" && myGroup != "print" && myGroup != "uri"
00587         && mimeTypeName != "application/octet-stream") {
00588         return "application/octet-stream";
00589     }
00590     return QString();
00591 }
00592 
00593 static QStringList parentMimeTypesList(const QString& mimeTypeName)
00594 {
00595     QStringList parents = KMimeTypeFactory::self()->parents(mimeTypeName);
00596     if (parents.isEmpty()) {
00597         const QString myParent = fallbackParent(mimeTypeName);
00598         if (!myParent.isEmpty())
00599             parents.append(myParent);
00600     }
00601     return parents;
00602 }
00603 
00604 QString KMimeType::parentMimeType() const
00605 {
00606     Q_D(const KMimeType);
00607 
00608     const QStringList parents = parentMimeTypesList(d->m_strName);
00609     if (!parents.isEmpty())
00610         return parents.first();
00611     return QString();
00612 }
00613 
00614 bool KMimeTypePrivate::inherits(const QString& mime) const
00615 {
00616     QStack<QString> toCheck;
00617     toCheck.push(m_strName);
00618     while (!toCheck.isEmpty()) {
00619         const QString current = toCheck.pop();
00620         if (current == mime)
00621             return true;
00622         Q_FOREACH(const QString& parent, parentMimeTypesList(current)) {
00623             toCheck.push(parent);
00624         }
00625     }
00626     return false;
00627 }
00628 
00629 bool KMimeType::is( const QString& mimeTypeName ) const
00630 {
00631     Q_D(const KMimeType);
00632     if (name() == mimeTypeName)
00633         return true;
00634     QString mime = KMimeTypeFactory::self()->resolveAlias(mimeTypeName);
00635     if (mime.isEmpty())
00636         mime = mimeTypeName;
00637     return d->inherits(mime);
00638 }
00639 
00640 QStringList KMimeType::parentMimeTypes() const
00641 {
00642     Q_D(const KMimeType);
00643     return parentMimeTypesList(d->m_strName);
00644 }
00645 
00646 static void collectParentMimeTypes(const QString& mime, QStringList& allParents)
00647 {
00648     QStringList parents = parentMimeTypesList(mime);
00649     Q_FOREACH(const QString& parent, parents) {
00650         // I would use QSet, but since order matters I better not
00651         if (!allParents.contains(parent))
00652             allParents.append(parent);
00653     }
00654     // We want a breadth-first search, so that the least-specific parent (octet-stream) is last
00655     // This means iterating twice, unfortunately.
00656     Q_FOREACH(const QString& parent, parents) {
00657         collectParentMimeTypes(parent, allParents);
00658     }
00659 }
00660 
00661 QStringList KMimeType::allParentMimeTypes() const
00662 {
00663     Q_D(const KMimeType);
00664     QStringList allParents;
00665     const QString canonical = KMimeTypeFactory::self()->resolveAlias(name());
00666     if (!canonical.isEmpty())
00667         allParents.append(canonical);
00668     collectParentMimeTypes(d->m_strName, allParents);
00669     return allParents;
00670 }
00671 
00672 QString KMimeType::defaultMimeType()
00673 {
00674     static const QString & s_strDefaultMimeType =
00675         KGlobal::staticQString( "application/octet-stream" );
00676     return s_strDefaultMimeType;
00677 }
00678 
00679 QString KMimeType::iconName( const KUrl& url) const
00680 {
00681     Q_D(const KMimeType);
00682     return d->iconName(url);
00683 }
00684 
00685 QStringList KMimeType::patterns() const
00686 {
00687     Q_D(const KMimeType);
00688     return d->m_lstPatterns;
00689 }
00690 
00691 void KMimeType::setPatterns(const QStringList& patterns)
00692 {
00693     Q_D(KMimeType);
00694     d->m_lstPatterns = patterns;
00695 }
00696 
00697 void KMimeType::internalClearData() // KDE5: remove
00698 {
00699     //Q_D(KMimeType);
00700     // Clear the data that KBuildMimeTypeFactory is going to refill - and only that data.
00701     //d->m_lstPatterns.clear(); // not true anymore
00702 }
00703 
00704 void KMimeType::setUserSpecifiedIcon(const QString& icon)
00705 {
00706     Q_D(KMimeType);
00707     d->m_iconName = icon;
00708 }
00709 
00710 QString KMimeType::userSpecifiedIconName() const
00711 {
00712     Q_D(const KMimeType);
00713     return d->m_iconName;
00714 }
00715 
00716 int KMimeType::sharedMimeInfoVersion()
00717 {
00718     static int s_version = 0;
00719     if (s_version == 0) {
00720         QProcess smi;
00721         const QString umd = KStandardDirs::findExe(QString::fromLatin1("update-mime-database"));
00722         if (umd.isEmpty()) {
00723             kWarning() << "update-mime-database not found!";
00724             s_version = -1;
00725         } else {
00726             smi.start(umd, QStringList() << QString::fromLatin1("-v"));
00727             smi.waitForStarted();
00728             smi.waitForFinished();
00729             const QString out = QString::fromLocal8Bit(smi.readAllStandardError());
00730             QRegExp versionRe(QString::fromLatin1("update-mime-database \\(shared-mime-info\\) (\\d+)\\.(\\d+)(\\.(\\d+))?"));
00731             if (versionRe.indexIn(out) > -1) {
00732                 s_version = KDE_MAKE_VERSION(versionRe.cap(1).toInt(), versionRe.cap(2).toInt(), versionRe.cap(4).toInt());
00733             } else {
00734                 kWarning() << "Unexpected version scheme from update-mime-database -v: got" << out;
00735                 s_version = -1;
00736             }
00737         }
00738     }
00739     return s_version;
00740 }
00741 
00742 QString KMimeType::mainExtension() const
00743 {
00744     Q_D(const KMimeType);
00745 
00746 #if 1 // HACK START - can be removed once shared-mime-info > 0.60 is used/required.
00747     // The idea was: first usable pattern from m_lstPatterns.
00748     // But update-mime-database makes a mess of the order of the patterns,
00749     // because it uses a hash internally.
00750     static const struct { const char* mime; const char* extension; } s_hardcodedMimes[] = {
00751         { "text/plain", ".txt" } };
00752     if (d->m_lstPatterns.count() > 1) {
00753         const QByteArray me = name().toLatin1();
00754         for (uint i = 0; i < sizeof(s_hardcodedMimes)/sizeof(*s_hardcodedMimes); ++i) {
00755             if (me == s_hardcodedMimes[i].mime)
00756                 return QString::fromLatin1(s_hardcodedMimes[i].extension);
00757         }
00758     }
00759 #endif // HACK END
00760 
00761      Q_FOREACH(const QString& pattern, d->m_lstPatterns) {
00762         // Skip if if looks like: README or *. or *.*
00763         // or *.JP*G or *.JP?
00764         if (pattern.startsWith("*.") &&
00765             pattern.length() > 2 &&
00766             pattern.indexOf('*', 2) < 0 && pattern.indexOf('?', 2) < 0) {
00767             return pattern.mid(1);
00768         }
00769     }
00770     // TODO we should also look into the parent mimetype's patterns, no?
00771     return QString();
00772 }
00773 
00774 void KMimeType::setParentMimeType(const QString&) // KDE5: remove
00775 {
00776     // Nothing. Don't ever call this. The method was internal, is now unused,
00777     // but is wrapped by bindings (because it was protected before).
00778 }

KDECore

Skip menu "KDECore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal