[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    [kdelibs/frameworks] /: Merge remote-tracking branch 'origin/KDE/4.10' into frameworks
From:       David Faure <faure () kde ! org>
Date:       2012-10-30 18:57:37
Message-ID: 20121030185737.C6D1CA6078 () git ! kde ! org
[Download RAW message or body]

Git commit 051638cabdc8d37e7a44d5af57ac7fc116c7d720 by David Faure.
Committed on 30/10/2012 at 19:25.
Pushed by dfaure into branch 'frameworks'.

Merge remote-tracking branch 'origin/KDE/4.10' into frameworks

Conflicts:
	kdecore/services/kmimeglobsfileparser.cpp [whole file is gone]
	kdecore/sycoca/kprotocolinfo.cpp [rewritten in kio; hand-merged]
	kdeui/widgets/kmainwindow.cpp [geometry handling, code is gone]
	kfile/kfileplacesitem.cpp
	kio/kio/kfileitem.cpp [tons of kurl/qmimetype differences for the big if(!d) patch]
	kio/tests/kfileitemtest.cpp [kurl]
	plasma/private/applethandle.cpp [namespace]
	plasma/runnermanager.cpp
	staging/kservice/src/services/kservicetypetrader.h [i18n]

M  +2    -1    kdeui/xmlgui/kxmlguifactory.cpp
M  +15   -15   kfile/kfileplacesitem.cpp
M  +6    -1    kfile/kfileplacesitem_p.h
M  +1    -0    kfile/kurlnavigator.cpp
M  +7    -6    khtml/rendering/render_replaced.cpp
M  +30   -3    kimgio/jp2.cpp
M  +219  -12   kio/kio/kfileitem.cpp
M  +11   -3    kio/kio/kfileitem.h
A  +21   -6    kio/kio/kprotocolinfo.cpp     [License: LGPL (v2)]
M  +8    -2    kio/tests/kfileitemtest.cpp
M  +1    -1    plasma/private/applethandle.cpp
M  +3    -0    plasma/runnermanager.cpp
A  +2    -1    staging/kde4support/autotests/kmimetypetest.cpp     [License: LGPL \
(v2/3+eV)] A  +3    -3    staging/kservice/src/services/kservicetypetrader.h     \
[License: LGPL (v2)] R  +1    -0    tier1/solid/src/solid/backends/udisks2/udisks2.h
R  +22   -18   tier1/solid/src/solid/backends/udisks2/udisksblock.cpp
R  +29   -12   tier1/solid/src/solid/backends/udisks2/udisksdevice.cpp
R  +1    -0    tier1/solid/src/solid/backends/udisks2/udisksdevice.h
R  +41   -0    tier1/solid/src/solid/backends/udisks2/udisksmanager.cpp
R  +1    -0    tier1/solid/src/solid/backends/udisks2/udisksmanager.h

http://commits.kde.org/kdelibs/051638cabdc8d37e7a44d5af57ac7fc116c7d720

diff --cc kfile/kfileplacesitem.cpp
index acd84d5,a7a62b5..b2a9046
--- a/kfile/kfileplacesitem.cpp
+++ b/kfile/kfileplacesitem.cpp
@@@ -26,9 -25,10 +26,10 @@@
  #include <kbookmarkmanager.h>
  #include <kiconloader.h>
  #include <kdirlister.h>
 -#include <klocale.h>
 +#include <klocalizedstring.h>
  #include <solid/block.h>
  #include <solid/opticaldisc.h>
+ #include <solid/opticaldrive.h>
  #include <solid/storageaccess.h>
  #include <solid/storagevolume.h>
  #include <solid/storagedrive.h>
@@@ -172,10 -176,10 +177,10 @@@ QVariant KFilePlacesItem::deviceData(in
          case Qt::DisplayRole:
              return d.description();
          case Qt::DecorationRole:
-             return KDE::icon(d.icon(), d.emblems());
 -            return KIcon(m_iconPath, 0, m_emblems);
++            return KDE::icon(m_iconPath, m_emblems);
          case KFilePlacesModel::UrlRole:
              if (m_access) {
 -                return QUrl(KUrl(m_access->filePath()));
 +                return QUrl::fromLocalFile(m_access->filePath());
              } else if (m_disc && (m_disc->availableContent() & \
Solid::OpticalDisc::Audio)!=0) {  QString device = d.as<Solid::Block>()->device();
                  return QUrl(QString("audiocd:/?device=%1").arg(device));
diff --cc kfile/kfileplacesitem_p.h
index cb2a27f,dec3e64..22b2adb
--- a/kfile/kfileplacesitem_p.h
+++ b/kfile/kfileplacesitem_p.h
@@@ -24,9 -24,9 +24,10 @@@
  #include <QtCore/QObject>
  #include <QtCore/QPointer>
  #include <QtCore/QModelIndex>
+ #include <QtCore/QStringList>
  #include <kbookmark.h>
  #include <solid/device.h>
 +#include <kurl.h>
  
  class KDirLister;
  namespace Solid
diff --cc kio/kio/kfileitem.cpp
index fce6644,54520d5..56007dc
--- a/kio/kio/kfileitem.cpp
+++ b/kio/kio/kfileitem.cpp
@@@ -528,15 -532,23 +533,23 @@@ void KFileItem::refresh(
  
  void KFileItem::refreshMimeType()
  {
+     if (!d)
+         return;
+ 
 -    d->m_pMimeType = 0;
 +    d->m_mimeType = QMimeType();
      d->m_bMimeTypeKnown = false;
      d->m_iconName.clear();
  }
  
 -void KFileItem::setUrl( const KUrl &url )
 +void KFileItem::setUrl( const QUrl &url )
  {
+     if (!d) {
+         kWarning() << "null item";
+         return;
+     }
+ 
      d->m_url = url;
 -    setName( url.fileName() );
 +    setName(QUrlPathInfo(url).fileName());
  }
  
  void KFileItem::setName( const QString& name )
@@@ -690,21 -769,26 +741,27 @@@ bool KFileItem::isSlow() cons
  
  QString KFileItem::mimetype() const
  {
+     if (!d)
+         return QString();
+ 
      KFileItem * that = const_cast<KFileItem *>(this);
 -    return that->determineMimeType()->name();
 +    return that->determineMimeType().name();
  }
  
 -KMimeType::Ptr KFileItem::determineMimeType() const
 +QMimeType KFileItem::determineMimeType() const
  {
+     if (!d)
 -        return KMimeType::Ptr();
++        return QMimeType();
+ 
 -    if ( !d->m_pMimeType || !d->m_bMimeTypeKnown )
 -    {
 +    if (!d->m_mimeType.isValid() || !d->m_bMimeTypeKnown) {
 +        QMimeDatabase db;
          bool isLocalUrl;
 -        KUrl url = mostLocalUrl(isLocalUrl);
 -
 -        d->m_pMimeType = KMimeType::findByUrl( url, d->m_fileMode, isLocalUrl );
 -        Q_ASSERT(d->m_pMimeType);
 -        //kDebug() << d << "finding final mimetype for" << url << ":" << \
d->m_pMimeType->name();  +        const QUrl url = mostLocalUrl(isLocalUrl);
 +        d->m_mimeType = db.mimeTypeForUrl(url);
 +        // was:  d->m_mimeType = KMimeType::findByUrl( url, d->m_fileMode, \
isLocalUrl );  +        // => we are no longer using d->m_fileMode for remote URLs.
 +        Q_ASSERT(d->m_mimeType.isValid());
 +        //qDebug() << d << "finding final mimetype for" << url << ":" << \
d->m_mimeType.name();  d->m_bMimeTypeKnown = true;
      }
  
@@@ -719,28 -806,11 +779,31 @@@ bool KFileItem::isMimeTypeKnown() cons
      return d->m_bMimeTypeKnown && d->m_guessedMimeType.isEmpty();
  }
  
 +static bool isDirectoryMounted(const QUrl& url)
 +{
 +    // Stating .directory files can cause long freezes when e.g. /home
 +    // uses autofs for every user's home directory, i.e. opening /home
 +    // in a file dialog will mount every single home directory.
 +    // These non-mounted directories can be identified by having 0 size.
 +    // There are also other directories with 0 size, such as /proc, that may
 +    // be mounted, but those are unlikely to contain .directory (and checking
 +    // this would require checking with KMountPoint).
 +
 +    // TODO: maybe this could be checked with KFileSystemType instead?
 +    KDE_struct_stat buff;
 +    if (KDE_stat(QFile::encodeName(url.toLocalFile()), &buff) == 0
 +        && S_ISDIR(buff.st_mode) && buff.st_size == 0) {
 +        return false;
 +    }
 +    return true;
 +}
 +
 +// KDE5 TODO: merge with comment()? Need to see what lxr says about the usage of \
both.  QString KFileItem::mimeComment() const
  {
+     if (!d)
+         return QString();
+ 
      const QString displayType = d->m_entry.stringValue( \
KIO::UDSEntry::UDS_DISPLAY_TYPE );  if (!displayType.isEmpty())
          return displayType;
@@@ -972,26 -1003,27 +1044,29 @@@ QString KFileItem::comment() cons
  // ## where is this used?
  QPixmap KFileItem::pixmap( int _size, int _state ) const
  {
+     if (!d)
+         return QPixmap();
+ 
 -    const QString iconName = d->m_entry.stringValue( KIO::UDSEntry::UDS_ICON_NAME \
                );
 -    if ( !iconName.isEmpty() )
 -        return DesktopIcon(iconName, _size, _state);
 +    const QString udsIconName = d->m_entry.stringValue( \
KIO::UDSEntry::UDS_ICON_NAME );  +    if ( !udsIconName.isEmpty() )
 +        return DesktopIcon(udsIconName, _size, _state);
 +
 +    QMimeDatabase db;
  
 -    if (!d->m_pMimeType) {
 +    if (!d->m_useIconNameCache && !d->m_mimeType.isValid()) {
          // No mimetype determined yet, go for a fast default icon
          if (S_ISDIR(d->m_fileMode)) {
 -            static const QString * defaultFolderIcon = 0;
 -            if ( !defaultFolderIcon ) {
 -                const KMimeType::Ptr mimeType = KMimeType::mimeType( \
                "inode/directory" );
 -                if ( mimeType )
 -                    defaultFolderIcon = &KGlobal::staticQString( \
                mimeType->iconName() );
 -               else
 +            static QString defaultFolderIcon;
 +            if ( defaultFolderIcon.isEmpty() ) {
 +                const QMimeType mimeType = db.mimeTypeForName("inode/directory");
 +                if (mimeType.isValid())
 +                    defaultFolderIcon = mimeType.iconName();
 +                else {
                      kWarning(7000) << "No mimetype for inode/directory could be \
found. Check your installation.";  +                    defaultFolderIcon = \
"unknown";  +                }
              }
 -            if ( defaultFolderIcon )
 -                return DesktopIcon( *defaultFolderIcon, _size, _state );
 -
 +            return DesktopIcon( defaultFolderIcon, _size, _state );
          }
          return DesktopIcon( "unknown", _size, _state );
      }
@@@ -1252,9 -1312,40 +1358,9 @@@ bool KFileItem::operator==(const KFileI
  
  bool KFileItem::operator!=(const KFileItem& other) const
  {
-     return d != other.d;
+     return !operator==(other);
  }
  
 -#ifndef KDE_NO_DEPRECATED
 -void KFileItem::setUDSEntry( const KIO::UDSEntry& _entry, const KUrl& _url,
 -                             bool _delayedMimeTypes, bool _urlIsDirectory )
 -{
 -    if (!d)
 -        return;
 -
 -    d->m_entry = _entry;
 -    d->m_url = _url;
 -    d->m_strName.clear();
 -    d->m_strText.clear();
 -    d->m_iconName.clear();
 -    d->m_strLowerCaseName.clear();
 -    d->m_pMimeType = 0;
 -    d->m_fileMode = KFileItem::Unknown;
 -    d->m_permissions = KFileItem::Unknown;
 -    d->m_bMarked = false;
 -    d->m_bLink = false;
 -    d->m_bIsLocalUrl = _url.isLocalFile();
 -    d->m_bMimeTypeKnown = false;
 -    d->m_hidden = KFileItemPrivate::Auto;
 -    d->m_guessedMimeType.clear();
 -    d->m_metaInfo = KFileMetaInfo();
 -    d->m_delayedMimeTypes = _delayedMimeTypes;
 -    d->m_useIconNameCache = false;
 -
 -    d->readUDSEntry( _urlIsDirectory );
 -    d->init();
 -}
 -#endif
 -
  KFileItem::operator QVariant() const
  {
      return qVariantFromValue(*this);
@@@ -1295,7 -1398,10 +1413,10 @@@ QString KFileItem::permissionsString() 
  // check if we need to cache this
  QString KFileItem::timeString( FileTimes which ) const
  {
+     if (!d)
+         return QString();
+ 
 -    return KGlobal::locale()->formatDateTime( d->time(which) );
 +    return KLocale::global()->formatDateTime( d->time(which) );
  }
  
  #ifndef KDE_NO_DEPRECATED
@@@ -1320,13 -1432,14 +1447,16 @@@ void KFileItem::setMetaInfo( const KFil
  
  KFileMetaInfo KFileItem::metaInfo(bool autoget, int what) const
  {
-     if (d && (isRegularFile() || isDir()) && autoget && !d->m_metaInfo.isValid())
+     if (!d)
+         return KFileMetaInfo();
+ 
+     if ((isRegularFile() || isDir()) && autoget && !d->m_metaInfo.isValid())
      {
          bool isLocalUrl;
 -        KUrl url(mostLocalUrl(isLocalUrl));
 -        d->m_metaInfo = KFileMetaInfo(url.toLocalFile(), mimetype(), \
(KFileMetaInfo::What)what);  +        QUrl url(mostLocalUrl(isLocalUrl));
 +        if (isLocalUrl) {
 +            d->m_metaInfo = KFileMetaInfo(url.toLocalFile(), mimetype(), \
(KFileMetaInfo::What)what);  +        }
      }
      return d->m_metaInfo;
  }
@@@ -1338,13 -1451,22 +1468,16 @@@ void KFileItem::assign( const KFileIte
  }
  #endif
  
 -KUrl KFileItem::mostLocalUrl(bool &local) const
 +QUrl KFileItem::mostLocalUrl(bool &local) const
  {
+     if (!d)
 -        return KUrl();
++        return QUrl();
+ 
 -    QString local_path = localPath();
 -
 -    if ( !local_path.isEmpty() )
 -    {
 +    const QString local_path = localPath();
 +    if ( !local_path.isEmpty() ) {
          local = true;
 -        KUrl url;
 -        url.setPath(local_path);
 -        return url;
 -    }
 -    else
 -    {
 +        return QUrl::fromLocalFile(local_path);
 +    } else {
          local = d->m_bIsLocalUrl;
          return d->m_url;
      }
@@@ -1358,19 -1480,43 +1491,43 @@@ QUrl KFileItem::mostLocalUrl() cons
  
  QDataStream & operator<< ( QDataStream & 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.d->m_url;
-     s << a.d->m_strName;
-     s << a.d->m_strText;
+     if (a.d) {
+         // We don't need to save/restore anything that refresh() invalidates,
+         // since that means we can re-determine those by ourselves.
+         s << a.d->m_url;
+         s << a.d->m_strName;
+         s << a.d->m_strText;
+     } else {
 -        s << KUrl();
++        s << QUrl();
+         s << QString();
+         s << QString();
+     }
+ 
      return s;
  }
  
  QDataStream & operator>> ( QDataStream & s, KFileItem & a )
  {
-     s >> a.d->m_url;
-     s >> a.d->m_strName;
-     s >> a.d->m_strText;
 -    KUrl url;
++    QUrl url;
+     QString strName, strText;
+ 
+     s >> url;
+     s >> strName;
+     s >> strText;
+ 
+     if (!a.d) {
+         kWarning() << "null item";
+         return s;
+     }
+ 
+     if (url.isEmpty()) {
+         a.d = 0;
+         return s;
+     }
+ 
+     a.d->m_url = url;
+     a.d->m_strName = strName;
+     a.d->m_strText = strText;
      a.d->m_bIsLocalUrl = a.d->m_url.isLocalFile();
      a.d->m_bMimeTypeKnown = false;
      a.refresh();
@@@ -1377,8 -1524,11 +1535,11 @@@
      return s;
  }
  
 -KUrl KFileItem::url() const
 +QUrl KFileItem::url() const
  {
+     if (!d)
 -        return KUrl();
++        return QUrl();
+ 
      return d->m_url;
  }
  
@@@ -1417,21 -1585,27 +1596,27 @@@ QString KFileItem::name( bool lowerCas
      return d->m_strLowerCaseName;
  }
  
 -KUrl KFileItem::targetUrl() const
 +QUrl KFileItem::targetUrl() const
  {
+     if (!d)
 -        return KUrl();
++        return QUrl();
+ 
      const QString targetUrlStr = d->m_entry.stringValue( \
KIO::UDSEntry::UDS_TARGET_URL );  if (!targetUrlStr.isEmpty())
 -      return KUrl(targetUrlStr);
 +        return QUrl(targetUrlStr);
      else
 -      return url();
 +        return url();
  }
  
 -KUrl KFileItem::nepomukUri() const
 +QUrl KFileItem::nepomukUri() const
  {
 -#ifndef KIO_NO_NEPOMUK
 +#if ! KIO_NO_NEPOMUK
+     if (!d)
 -        return KUrl();
++        return QUrl();
+ 
      const QString nepomukUriStr = d->m_entry.stringValue( \
KIO::UDSEntry::UDS_NEPOMUK_URI );  if(!nepomukUriStr.isEmpty()) {
 -        return KUrl(nepomukUriStr);
 +        return QUrl(nepomukUriStr);
      }
      else if(targetUrl().isLocalFile()) {
          return targetUrl();
@@@ -1456,30 -1630,27 +1641,33 @@@
   * If delayedMimeTypes isn't set, then we always go to the Final state directly.
   */
  
 -KMimeType::Ptr KFileItem::mimeTypePtr() const
 +QMimeType KFileItem::currentMimeType() const
  {
+     if (!d)
 -        return KMimeType::Ptr();
++        return QMimeType();
+ 
 -    if (!d->m_pMimeType) {
 +    if (!d->m_mimeType.isValid()) {
          // On-demand fast (but not always accurate) mimetype determination
          Q_ASSERT(!d->m_url.isEmpty());
 -        bool isLocalUrl;
 -        KUrl url = mostLocalUrl(isLocalUrl);
 -        int accuracy;
 -        d->m_pMimeType = KMimeType::findByUrl( url, d->m_fileMode, isLocalUrl,
 -                                               // use fast mode if delayed mimetype \
                determination can refine it later
 -                                               d->m_delayedMimeTypes, &accuracy );
 -        // If we used the "fast mode" (no sniffing), and we didn't get a perfect \
                (extension-based) match,
 -        // then determineMimeType will be able to do better.
 -        const bool canDoBetter = d->m_delayedMimeTypes && accuracy < 100;
 -        //kDebug() << "finding mimetype for" << url << ":" << \
                d->m_pMimeType->name() << "canDoBetter=" << canDoBetter;
 -        d->m_bMimeTypeKnown = !canDoBetter;
 +        QMimeDatabase db;
 +        const QUrl url = mostLocalUrl();
 +        if (d->m_delayedMimeTypes) {
 +            const QList<QMimeType> mimeTypes = db.mimeTypesForFileName(url.path());
 +            if (mimeTypes.isEmpty()) {
 +                d->m_mimeType = db.mimeTypeForName("application/octet-stream");
 +                d->m_bMimeTypeKnown = false;
 +            } else {
 +                d->m_mimeType = mimeTypes.first();
 +                // If there were conflicting globs. determineMimeType will be able \
to do better.  +                d->m_bMimeTypeKnown = (mimeTypes.count() == 1);
 +            }
 +        } else {
 +            // ## d->m_fileMode isn't used anymore (for remote urls)
 +            d->m_mimeType = db.mimeTypeForUrl(url);
 +            d->m_bMimeTypeKnown = true;
 +        }
      }
 -    return d->m_pMimeType;
 +    return d->m_mimeType;
  }
  
  KIO::UDSEntry KFileItem::entry() const
diff --cc kio/kio/kprotocolinfo.cpp
index 296262c,0000000..542fd82
mode 100644,000000..100644
--- a/kio/kio/kprotocolinfo.cpp
+++ b/kio/kio/kprotocolinfo.cpp
@@@ -1,279 -1,0 +1,294 @@@
 +/* This file is part of the KDE libraries
 +   Copyright (C) 1999 Torben Weis <weis@kde.org>
 +   Copyright (C) 2003 Waldo Bastian <bastian@kde.org>
 +   Copyright     2012 David Faure <faure@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 version 2 as published by the Free Software Foundation.
 +
 +   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.
 +*/
 +
 +#include "kprotocolinfo.h"
 +#include "kprotocolinfo_p.h"
 +#include "kprotocolinfofactory_p.h"
 +
 +#include <kmimetypetrader.h>
 +#include <kconfig.h>
 +#include <kconfiggroup.h>
 +#include <QUrl>
 +
 +//
 +// Internal functions:
 +//
 +KProtocolInfoPrivate::KProtocolInfoPrivate(const QString &path)
 +{
 +  KConfig sconfig(path);
 +  KConfigGroup config(&sconfig, "Protocol");
 +
 +  m_name = config.readEntry("protocol");
 +  m_exec = config.readPathEntry("exec", QString());
 +  m_isSourceProtocol = config.readEntry("source", true);
 +  m_isHelperProtocol = config.readEntry("helper", false);
 +  m_supportsReading = config.readEntry("reading", false);
 +  m_supportsWriting = config.readEntry("writing", false);
 +  m_supportsMakeDir = config.readEntry("makedir", false);
 +  m_supportsDeleting = config.readEntry("deleting", false);
 +  m_supportsLinking = config.readEntry("linking", false);
 +  m_supportsMoving = config.readEntry("moving", false);
 +  m_supportsOpening = config.readEntry("opening", false);
 +  m_canCopyFromFile = config.readEntry("copyFromFile", false);
 +  m_canCopyToFile = config.readEntry("copyToFile", false);
 +  m_canRenameFromFile = config.readEntry("renameFromFile", false);
 +  m_canRenameToFile = config.readEntry("renameToFile", false);
 +  m_canDeleteRecursive = config.readEntry("deleteRecursive", false);
 +  const QString fnu = config.readEntry("fileNameUsedForCopying", "FromURL");
 +  m_fileNameUsedForCopying = KProtocolInfo::FromUrl;
 +  if (fnu == QLatin1String("Name"))
 +    m_fileNameUsedForCopying = KProtocolInfo::Name;
 +  else if (fnu == QLatin1String("DisplayName"))
 +    m_fileNameUsedForCopying = KProtocolInfo::DisplayName;
 +
 +  m_listing = config.readEntry("listing", QStringList());
 +  // Many .protocol files say "Listing=false" when they really mean "Listing=" \
(i.e. unsupported)  +  if (m_listing.count() == 1 && m_listing.first() == \
QLatin1String("false"))  +    m_listing.clear();
 +  m_supportsListing = (m_listing.count() > 0);
 +  m_defaultMimetype = config.readEntry("defaultMimetype");
 +  m_determineMimetypeFromExtension = \
config.readEntry("determineMimetypeFromExtension", true);  +  m_archiveMimeTypes = \
config.readEntry("archiveMimetype", QStringList());  +  m_icon = \
config.readEntry("Icon");  +  m_config = config.readEntry("config", m_name);
 +  m_maxSlaves = config.readEntry("maxInstances", 1);
 +  m_maxSlavesPerHost = config.readEntry("maxInstancesPerHost", 0);
 +
 +  QString tmp = config.readEntry("input");
 +  if (tmp == QLatin1String("filesystem"))
 +    m_inputType = KProtocolInfo::T_FILESYSTEM;
 +  else if (tmp == QLatin1String("stream"))
 +    m_inputType = KProtocolInfo::T_STREAM;
 +  else
 +    m_inputType = KProtocolInfo::T_NONE;
 +
 +  tmp = config.readEntry("output");
 +  if (tmp == QLatin1String("filesystem"))
 +    m_outputType = KProtocolInfo::T_FILESYSTEM;
 +  else if (tmp == QLatin1String("stream"))
 +    m_outputType = KProtocolInfo::T_STREAM;
 +  else
 +    m_outputType = KProtocolInfo::T_NONE;
 +
 +  m_docPath = config.readPathEntry("X-DocPath", QString());
 +  if (m_docPath.isEmpty())
 +    m_docPath = config.readPathEntry("DocPath", QString());
 +  m_protClass = config.readEntry("Class").toLower();
 +  if (m_protClass[0] != QLatin1Char(':'))
 +     m_protClass.prepend(QLatin1Char(':'));
 +
 +  const QStringList extraNames = config.readEntry("ExtraNames", QStringList());
 +  const QStringList extraTypes = config.readEntry("ExtraTypes", QStringList());
 +  QStringList::const_iterator it = extraNames.begin();
 +  QStringList::const_iterator typeit = extraTypes.begin();
 +  for(; it != extraNames.end() && typeit != extraTypes.end(); ++it, ++typeit) {
 +      QVariant::Type type = QVariant::nameToType((*typeit).toLatin1());
 +      // currently QVariant::Type and ExtraField::Type use the same subset of \
values, so we can just cast.  +      \
m_extraFields.append(KProtocolInfo::ExtraField(*it, \
static_cast<KProtocolInfo::ExtraField::Type>(type)));  +  }
 +
 +  m_showPreviews = config.readEntry("ShowPreviews", m_protClass == \
QLatin1String(":local"));  +
 +  m_capabilities = config.readEntry("Capabilities", QStringList());
 +  m_proxyProtocol = config.readEntry("ProxiedBy");
 +}
 +
 +//
 +// Static functions:
 +//
 +
 +QStringList KProtocolInfo::protocols()
 +{
 +  return KProtocolInfoFactory::self()->protocols();
 +}
 +
 +bool KProtocolInfo::isFilterProtocol(const QString& _protocol)
 +{
 +  // We call the findProtocol directly (not via KProtocolManager) to bypass any \
proxy settings.  +  KProtocolInfoPrivate* prot = \
KProtocolInfoFactory::self()->findProtocol(_protocol);  +  if (!prot)
 +    return false;
 +
 +  return !prot->m_isSourceProtocol;
 +}
 +
 +QString KProtocolInfo::icon(const QString& _protocol)
 +{
 +  // We call the findProtocol directly (not via KProtocolManager) to bypass any \
proxy settings.  +  KProtocolInfoPrivate * prot = \
KProtocolInfoFactory::self()->findProtocol(_protocol);  +  if (!prot)
 +    return QString();
 +
 +  return prot->m_icon;
 +}
 +
 +QString KProtocolInfo::config(const QString& _protocol)
 +{
 +  // We call the findProtocol directly (not via KProtocolManager) to bypass any \
proxy settings.  +  KProtocolInfoPrivate * prot = \
KProtocolInfoFactory::self()->findProtocol(_protocol);  +  if (!prot)
 +    return QString();
 +
 +  return QString::fromLatin1("kio_%1rc").arg(prot->m_config);
 +}
 +
 +int KProtocolInfo::maxSlaves(const QString& _protocol)
 +{
 +  KProtocolInfoPrivate * prot = \
KProtocolInfoFactory::self()->findProtocol(_protocol);  +  if (!prot)
 +    return 1;
 +
 +  return prot->m_maxSlaves;
 +}
 +
 +int KProtocolInfo::maxSlavesPerHost(const QString& _protocol)
 +{
 +  KProtocolInfoPrivate * prot = \
KProtocolInfoFactory::self()->findProtocol(_protocol);  +  if (!prot)
 +    return 0;
 +
 +  return prot->m_maxSlavesPerHost;
 +}
 +
 +bool KProtocolInfo::determineMimetypeFromExtension(const QString &_protocol)
 +{
 +  KProtocolInfoPrivate * prot = \
KProtocolInfoFactory::self()->findProtocol(_protocol);  +  if (!prot)
 +    return true;
 +
 +  return prot->m_determineMimetypeFromExtension;
 +}
 +
 +QString KProtocolInfo::exec(const QString& protocol)
 +{
 +  KProtocolInfoPrivate * prot = \
KProtocolInfoFactory::self()->findProtocol(protocol); ++
++  // We have up to two sources of data:
++  // 1) the exec line of the .protocol file, if there's one (could be a kioslave or \
a helper app) ++  // 2) the application associated with x-scheme-handler/<protocol> \
if there's one ++
++  // If both exist, then:
++  //  A) if the .protocol file says "launch an application", then the new-style \
handler-app has priority ++  //  B) but if the .protocol file is for a kioslave (e.g. \
kio_http) then this has priority over ++  //     firefox or chromium saying \
x-scheme-handler/http. Gnome people want to send all HTTP urls ++  //     to a \
webbrowser, but we want mimetype-determination-in-calling-application by default ++  \
//     (the user can configure a BrowserApplication though) ++
++  QString helperExe;
++  const KService::Ptr service = \
KMimeTypeTrader::self()->preferredService(QString::fromLatin1("x-scheme-handler/") + \
protocol); ++  if (service) {
++      helperExe = service->exec();
++      if (prot && prot->m_isHelperProtocol)
++          return helperExe; // for helper protocols, the handler app has priority \
over the hardcoded one (see A above) ++  }
 +  if (prot) {
 +      return prot->m_exec;
 +  }
 +
-   // Maybe it's "helper protocol", i.e. launches an app?
-   const KService::Ptr service = \
KMimeTypeTrader::self()->preferredService(QString::fromLatin1("x-scheme-handler/") + \
                protocol);
-   if (service)
-       return service->exec();
- 
-   return QString();
++  // If there's no protocol file, then return the handler app if any, otherwise \
empty string ++  return helperExe;
 +}
 +
 +KProtocolInfo::ExtraFieldList KProtocolInfo::extraFields(const QUrl &url)
 +{
 +  KProtocolInfoPrivate * prot = \
KProtocolInfoFactory::self()->findProtocol(url.scheme());  +  if (!prot)
 +    return ExtraFieldList();
 +
 +  return prot->m_extraFields;
 +}
 +
 +QString KProtocolInfo::docPath(const QString& _protocol)
 +{
 +  KProtocolInfoPrivate * prot = \
KProtocolInfoFactory::self()->findProtocol(_protocol);  +  if (!prot)
 +    return QString();
 +
 +  return prot->m_docPath;
 +}
 +
 +QString KProtocolInfo::protocolClass(const QString& _protocol)
 +{
 +  KProtocolInfoPrivate * prot = \
KProtocolInfoFactory::self()->findProtocol(_protocol);  +  if (!prot)
 +    return QString();
 +
 +  return prot->m_protClass;
 +}
 +
 +bool KProtocolInfo::showFilePreview(const QString& _protocol)
 +{
 +  KProtocolInfoPrivate * prot = \
KProtocolInfoFactory::self()->findProtocol(_protocol);  +  const bool defaultSetting \
= prot ? prot->m_showPreviews : false;  +
 +  KConfigGroup group(KSharedConfig::openConfig(), "PreviewSettings");
 +  return group.readEntry(_protocol, defaultSetting);
 +}
 +
 +QStringList KProtocolInfo::capabilities(const QString& _protocol)
 +{
 +  KProtocolInfoPrivate * prot = \
KProtocolInfoFactory::self()->findProtocol(_protocol);  +  if (!prot)
 +    return QStringList();
 +
 +  return prot->m_capabilities;
 +}
 +
 +QString KProtocolInfo::proxiedBy(const QString& _protocol)
 +{
 +  KProtocolInfoPrivate * prot = \
KProtocolInfoFactory::self()->findProtocol(_protocol);  +  if (!prot)
 +    return QString();
 +
 +  return prot->m_proxyProtocol;
 +}
 +
 +bool KProtocolInfo::isFilterProtocol(const QUrl &url)
 +{
 +    return isFilterProtocol(url.scheme());
 +}
 +
 +bool KProtocolInfo::isHelperProtocol(const QUrl &url)
 +{
 +    return isHelperProtocol(url.scheme());
 +}
 +
 +bool KProtocolInfo::isHelperProtocol(const QString &protocol)
 +{
 +  // We call the findProtocol directly (not via KProtocolManager) to bypass any \
proxy settings.  +  KProtocolInfoPrivate * prot = \
KProtocolInfoFactory::self()->findProtocol(protocol);  +  if (prot)
 +      return prot->m_isHelperProtocol;
 +
 +  const KService::Ptr service = \
KMimeTypeTrader::self()->preferredService(QString::fromLatin1("x-scheme-handler/") + \
protocol);  +  return !service.isNull();
 +}
 +
 +bool KProtocolInfo::isKnownProtocol(const QUrl &url)
 +{
 +    return isKnownProtocol(url.scheme());
 +}
 +
 +bool KProtocolInfo::isKnownProtocol(const QString &protocol)
 +{
 +  // We call the findProtocol (const QString&) to bypass any proxy settings.
 +  KProtocolInfoPrivate * prot = \
KProtocolInfoFactory::self()->findProtocol(protocol);  +  return prot || \
isHelperProtocol(protocol);  +}
diff --cc kio/tests/kfileitemtest.cpp
index 0d066eb,e61476e..55c72d9
--- a/kio/tests/kfileitemtest.cpp
+++ b/kio/tests/kfileitemtest.cpp
@@@ -242,12 -245,14 +246,14 @@@ void KFileItemTest::testMimeTypeOnDeman
  
  void KFileItemTest::testCmp()
  {
 -    KTemporaryFile file;
 +    QTemporaryFile file;
      QVERIFY(file.open());
  
 -    KFileItem fileItem(KFileItem::Unknown, KFileItem::Unknown, \
                KUrl(file.fileName()), true /*on demand*/);
 -    KFileItem fileItem2(KFileItem::Unknown, KFileItem::Unknown, \
KUrl(file.fileName()), false);  +    KFileItem fileItem(KFileItem::Unknown, \
KFileItem::Unknown, QUrl::fromLocalFile(file.fileName()), true /*on demand*/);  +    \
KFileItem fileItem2(KFileItem::Unknown, KFileItem::Unknown, \
                QUrl::fromLocalFile(file.fileName()), false);
-     QVERIFY(fileItem != fileItem2); // created independently so not 'equal'
+     QVERIFY(fileItem == fileItem2); // created independently, but still 'equal'
+     QVERIFY(fileItem.d != fileItem2.d);
+     QVERIFY(!(fileItem != fileItem2));
      QVERIFY(fileItem.cmp(fileItem2));
  }
  
diff --cc plasma/private/applethandle.cpp
index 3348e5f,6e6a283..d8e32be
--- a/plasma/private/applethandle.cpp
+++ b/plasma/private/applethandle.cpp
@@@ -236,7 -237,7 +236,7 @@@ void AppletHandle::paint(QPainter *pain
  
          QLinearGradient g(QPoint(0, 0), QPoint(m_decorationRect.width(), 0));
          //fading out panel
-         if (m_applet->backgroundHints() != Plasma::NoBackground &&
 -        if (m_applet && m_applet->backgroundHints() != Plasma::Applet::NoBackground \
&& ++        if (m_applet && m_applet->backgroundHints() != Plasma::NoBackground &&
              m_rect.height() > qreal(minimumHeight()) * 1.25) {
              if (m_buttonsOnRight) {
                  qreal opaquePoint =
diff --cc plasma/runnermanager.cpp
index bb0708b,3c46f8c..b016eba
--- a/plasma/runnermanager.cpp
+++ b/plasma/runnermanager.cpp
@@@ -296,11 -290,12 +296,14 @@@ public
          }
  
          if (runner) {
 +#ifndef NDEBUG
              kDebug() << "================= loading runner:" << service->name() << \
"=================";  +#endif
              QObject::connect(runner, SIGNAL(matchingSuspended(bool)), q, \
                SLOT(runnerMatchingSuspended(bool)));
 -            QMetaObject::invokeMethod(runner, "init");
 +            runner->init();
+             if (prepped) {
+                 emit runner->prepare();
+             }
          }
  
          return runner;
diff --cc staging/kde4support/autotests/kmimetypetest.cpp
index 36f9f2d,0000000..2833167
mode 100644,000000..100644
--- a/staging/kde4support/autotests/kmimetypetest.cpp
+++ b/staging/kde4support/autotests/kmimetypetest.cpp
@@@ -1,881 -1,0 +1,882 @@@
 +/*
 + *  Copyright (C) 2005-2009 David Faure   <faure@kde.org>
 + *
 + *  This library is free software; you can redistribute it and/or modify
 + *  it under the terms of the GNU Lesser General Public License as published by
 + *  the Free Software Foundation; either version 2 of the License or ( at
 + *  your option ) version 3 or, at the discretion of KDE e.V. ( which shall
 + *  act as a proxy as in section 14 of the GPLv3 ), 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.
 + */
 +
 +#include "kmimetypetest.h"
 +
 +#include <kdefakes.h>
 +#include <kde_file.h>
 +#include <kdeversion.h> // KDE_MAKE_VERSION
 +#include <kmimetype.h>
 +#include <ksycoca.h>
 +#include <kuser.h>
 +#include <qtemporarydir.h>
 +#include <kconfiggroup.h>
 +#include <kdebug.h>
 +
 +#include <qtest_kde.h> // WARNING: do not port to qtest.h without adding a putenv \
for XDG_DATA_HOME! User data loss will occur otherwise.  +#include <qstandardpaths.h>
 +#include <qprocess.h>
 +#include <kmimetypetrader.h>
 +#include <kservicetypetrader.h>
 +#include <kmimetyperepository_p.h>
 +#include <qtemporaryfile.h>
 +#include <kdesktopfile.h>
 +
 +#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
 +#include <QtConcurrent>
 +#endif
 +
 +int initializeLang()
 +{
 +    qputenv("LC_ALL", "en_US");
 +    qputenv("LANG", "en_US");
 +    return 0;
 +}
 +
 +// Set LANG before QCoreApplication is created
 +Q_CONSTRUCTOR_FUNCTION(initializeLang)
 +
 +void KMimeTypeTest::initTestCase()
 +{
 +    // Clean up local xdg dir in case of leftover mimetype definitions
 +    const QString xdgDir = QString::fromLocal8Bit(getenv("XDG_DATA_HOME"));
 +    if (!xdgDir.isEmpty()) {
 +#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
 +        QTemporaryDir::removeRecursively(xdgDir);
 +#else
 +        QDir d_(xdgDir);
 +        d_.removeRecursively();
 +#endif
 +        // No need to run update-mime-database here, the dir is entirely gone.
 +    }
 +
 +    bool mustUpdateKSycoca = false;
 +
 +    // Create fake text/x-patch part.
 +    const QString fakePatchPart = \
QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + \
QLatin1String("/kde5/services/") + "fakepatchpart.desktop";  +    const bool \
mustCreatePatchPart = !QFile::exists(fakePatchPart);  +    if (mustCreatePatchPart) {
 +        mustUpdateKSycoca = true;
 +        KDesktopFile file(fakePatchPart);
 +        KConfigGroup group = file.desktopGroup();
 +        group.writeEntry("Name", "FakePatchPart");
 +        group.writeEntry("Type", "Service");
 +        group.writeEntry("X-KDE-Library", "fakepatchpart");
 +        group.writeEntry("ServiceTypes", "KParts/ReadOnlyPart");
 +        group.writeEntry("MimeType", "text/x-diff;"); // Use an alias on purpose, \
to test if that works  +        group.writeEntry("InitialPreference", 5);
 +    }
 +
 +    // Create fake text/plain part with a higher initial preference than the patch \
part.  +    const QString fakePart = \
QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + \
QLatin1String("/kde5/services/") + "faketextpart.desktop";  +    const bool \
mustCreate = !QFile::exists(fakePart);  +    if (mustCreate) {
 +        mustUpdateKSycoca = true;
 +        KDesktopFile file(fakePart);
 +        KConfigGroup group = file.desktopGroup();
 +        group.writeEntry("Name", "FakePart");
 +        group.writeEntry("Type", "Service");
 +        group.writeEntry("X-KDE-Library", "faketextpart");
 +        group.writeEntry("ServiceTypes", "KParts/ReadOnlyPart");
 +        group.writeEntry("MimeType", "text/plain;");
 +        group.writeEntry("InitialPreference",100);
 +    }
 +
 +    // Create fake text/plain ktexteditor plugin.
 +    const QString fakePlugin = \
QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + \
QLatin1String("/kde5/services/") + "faketextplugin.desktop";  +    const bool \
mustCreatePlugin = !QFile::exists(fakePlugin);  +    if (mustCreatePlugin) {
 +        mustUpdateKSycoca = true;
 +        KDesktopFile file(fakePlugin);
 +        KConfigGroup group = file.desktopGroup();
 +        group.writeEntry("Name", "FakePlugin");
 +        group.writeEntry("Type", "Service");
 +        group.writeEntry("X-KDE-Library", "faketextplugin");
 +        group.writeEntry("ServiceTypes", "KPluginInfo");
 +        group.writeEntry("MimeType", "text/plain;");
 +    }
 +
 +    // Create fake "NotShowIn=KDE" service
 +    m_nonKdeApp = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation) \
+ QLatin1Char('/') + "fake_nonkde_application.desktop";  +    const bool \
mustCreateNonKdeApp = !QFile::exists(m_nonKdeApp);  +    if (mustCreateNonKdeApp) {
 +        mustUpdateKSycoca = true;
 +        KDesktopFile file(m_nonKdeApp);
 +        KConfigGroup group = file.desktopGroup();
 +        group.writeEntry("Name", "NonKDEApp");
 +        group.writeEntry("Type", "Application");
 +        group.writeEntry("Exec", "xterm");
 +        group.writeEntry("NotShowIn", "KDE;FVWM;");
 +        group.writeEntry("MimeType", "text/plain;");
 +        group.writeEntry("InitialPreference", "50");
 +        group.writeEntry("Categories", "Qt;KDE;");
 +    }
 +
 +    // Create fake text/plain app
 +    m_textPlainApp = \
QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation) + \
QLatin1Char('/') + "fake_textplain_application.desktop";  +    const bool \
mustCreateTextPlainApp = !QFile::exists(m_textPlainApp);  +    if \
(mustCreateTextPlainApp) {  +        mustUpdateKSycoca = true;
 +        KDesktopFile file(m_textPlainApp);
 +        KConfigGroup group = file.desktopGroup();
 +        group.writeEntry("Name", "NonKDEApp");
 +        group.writeEntry("Type", "Application");
 +        group.writeEntry("Exec", "xterm");
 +        group.writeEntry("MimeType", "text/plain;");
 +        group.writeEntry("InitialPreference", "40");
 +        group.writeEntry("Categories", "Qt;KDE;");
 +    }
 +
 +    if ( mustUpdateKSycoca ) {
 +        // Update ksycoca in ~/.kde-unit-test after creating the above
 +        QProcess::execute(QStandardPaths::findExecutable(KBUILDSYCOCA_EXENAME));
 +    }
 +
 +    KService::Ptr fakeApp = \
KService::serviceByStorageId("fake_nonkde_application.desktop");  +    \
QVERIFY(fakeApp); // it should be found.  +    \
QVERIFY(KService::serviceByDesktopPath(m_nonKdeApp)); // the desktoppath is the full \
path nowadays  +}
 +
 +void KMimeTypeTest::cleanupTestCase()
 +{
 +    // If I want the konqueror unit tests to work, then I better not have a \
non-working part  +    // as the preferred part for text/plain...
 +    const QString fakePatchPart = \
QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + \
QLatin1String("/kde5/services/") + "fakepatchpart.desktop";  +    \
QFile::remove(fakePatchPart);  +    const QString fakePart = \
QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + \
QLatin1String("/kde5/services/") + "faketextpart.desktop";  +    \
QFile::remove(fakePart);  +    const QString fakePlugin = \
QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + \
QLatin1String("/kde5/services/") + "faketextplugin.desktop";  +    \
QFile::remove(fakePlugin);  +    QProcess proc;
 +    proc.setProcessChannelMode(QProcess::MergedChannels); // silence kbuildsycoca \
output  +    proc.start(QStandardPaths::findExecutable(KBUILDSYCOCA_EXENAME));
 +    proc.waitForFinished();
 +}
 +
 +QTEST_KDEMAIN_CORE( KMimeTypeTest )
 +
 +void KMimeTypeTest::testByName()
 +{
 +    KMimeType::Ptr s0 = KMimeType::mimeType("application/x-zerosize");
 +    QVERIFY( s0 );
 +    QCOMPARE( s0->name(), QString::fromLatin1("application/x-zerosize") );
 +    QCOMPARE( s0->comment(), QString::fromLatin1("empty document") );
 +
 +    KMimeType::Ptr s0Again = KMimeType::mimeType("application/x-zerosize");
 +    QCOMPARE(s0Again->name(), s0->name());
 +    QVERIFY(s0Again != s0);
 +
 +    KMimeType::Ptr s1 = KMimeType::mimeType("text/plain");
 +    QVERIFY( s1 );
 +    QCOMPARE( s1->name(), QString::fromLatin1("text/plain") );
 +    //qDebug("Comment is %s", qPrintable(s1->comment()) );
 +
 +    KMimeType::Ptr krita = KMimeType::mimeType("application/x-krita");
 +    QVERIFY( krita );
 +
 +    // Test <comment> parsing with application/rdf+xml which has the english \
comment after the other ones  +    KMimeType::Ptr rdf = \
KMimeType::mimeType("application/rdf+xml");  +    QVERIFY(rdf);
 +    QCOMPARE(rdf->comment(), QString::fromLatin1("RDF file"));
 +
 +    KMimeType::Ptr bzip2 = KMimeType::mimeType("application/x-bzip2");
 +    QVERIFY( bzip2 );
 +    QCOMPARE(bzip2->comment(), QString::fromLatin1("Bzip archive"));
 +
 +    KMimeType::Ptr defaultMime = KMimeType::mimeType("application/octet-stream");
 +    QVERIFY(defaultMime);
 +    QVERIFY(defaultMime->isDefault());
 +}
 +
 +void KMimeTypeTest::testIcons()
 +{
 +    if ( !KUser().isSuperUser() ) // Can't test this one if running as root
 +    {
 +        QString emptyString; // gcc-3.3 workaround
 +	QTemporaryDir tmp (emptyString);
 +	QFile(tmp.path()).setPermissions(0);
 +        tmp.setAutoRemove( true );
 +        //KUrl url( tmp.path() );
 +        //QCOMPARE(KIO::iconNameForUrl(url), "inode-directory"); // was \
folder_locked, but we don't have that anymore - TODO  \
+	QFile(tmp.path()).setPermissions(QFile::ReadOwner|QFile::ExeOwner); // so we can \
'rm -rf' it  +    }
 +}
 +
 +
 +void KMimeTypeTest::testFindByPathUsingFileName_data()
 +{
 +    QTest::addColumn<QString>("fileName");
 +    QTest::addColumn<QString>("expectedMimeType");
 +    // Maybe we could also add a expectedAccuracy column...
 +
 +    QTest::newRow("text") << "textfile.txt" << "text/plain";
 +    QTest::newRow("case-insensitive search") << "textfile.TxT" << "text/plain";
 +    // With QMime, this needs shared-mime-info > 0.91. Earlier versions wrote .Z to \
the mime.cache file...  +    if (KMimeType::sharedMimeInfoVersion() > \
KDE_MAKE_VERSION(0, 91, 0)) {  +        QTest::newRow("case-insensitive match on a \
non-lowercase glob") << "foo.z" << "application/x-compress";  +    }
 +
 +    QTest::newRow("case-sensitive uppercase match") << "textfile.C" << \
"text/x-c++src";  +    QTest::newRow("case-sensitive lowercase match") << \
"textfile.c" << "text/x-csrc";  +    QTest::newRow("case-sensitive long-extension \
match") << "foo.PS.gz" << "application/x-gzpostscript";  +    \
QTest::newRow("case-sensitive-only match") << "core" << "application/x-core";  +    \
QTest::newRow("case-sensitive-only match") << "Core" << "application/octet-stream"; \
// #198477  +
 +    QTest::newRow("desktop file") << "foo.desktop" << "application/x-desktop";
 +    QTest::newRow("old kdelnk file is x-desktop too") << "foo.kdelnk" << \
"application/x-desktop";  +    QTest::newRow("double-extension file") << \
"foo.tar.bz2" << "application/x-bzip-compressed-tar";  +    \
QTest::newRow("single-extension file") << "foo.bz2" << "application/x-bzip";  +    \
QTest::newRow(".doc should assume msword") << "somefile.doc" << "application/msword"; \
// #204139  +    QTest::newRow("glob that uses [] syntax, 1") << "Makefile" << \
"text/x-makefile";  +    QTest::newRow("glob that uses [] syntax, 2") << "makefile" \
<< "text/x-makefile";  +    QTest::newRow("glob that ends with *, no extension") << \
"README" << "text/x-readme";  +    QTest::newRow("glob that ends with *, extension") \
<< "README.foo" << "text/x-readme";  +    QTest::newRow("glob that ends with *, also \
matches *.txt. Higher weight wins.") << "README.txt" << "text/plain";  +    \
QTest::newRow("glob that ends with *, also matches *.nfo. Higher weight wins.") << \
"README.nfo" << "text/x-nfo";  +    // fdo bug 15436, needs shared-mime-info >= 0.40 \
(and this tests the globs2-parsing code).  +    QTest::newRow("glob that ends with *, \
also matches *.pdf. *.pdf has higher weight") << "README.pdf" << "application/pdf";  \
+    QTest::newRow("directory") << "/" << "inode/directory";  +    \
QTest::newRow("doesn't exist, no extension") << "IDontExist" << \
"application/octet-stream";  +    QTest::newRow("doesn't exist but has known \
extension") << "IDontExist.txt" << "text/plain";  +
 +    // Can't use KIconLoader since this is a "without GUI" test.
 +    if (QStandardPaths::locate(QStandardPaths::GenericDataLocation, \
QLatin1String("icons/") + "oxygen", QStandardPaths::LocateDirectory).isEmpty()) {  +  \
kWarning() << "oxygen not found";  +    } else {
 +        QString fh = QStandardPaths::locate(QStandardPaths::GenericDataLocation, \
QLatin1String("icons/") + "oxygen/22x22/places/folder.png" );  +        QVERIFY( \
!fh.isEmpty() ); // if the file doesn't exist, please fix the above to point to an \
existing icon  +        QTest::newRow("png image") << fh << "image/png";
 +    }
 +
 +    const QString exePath = QStandardPaths::findExecutable("update-mime-database");
 +    QVERIFY2(!exePath.isEmpty(), "update-mime-database not found. Isn't \
shared-mime-info installed, and in your $PATH?");  +#ifdef Q_OS_WIN
 +    const QString executableType = \
QString::fromLatin1("application/x-ms-dos-executable");  +#else
 +    const QString executableType = QString::fromLatin1("application/x-executable");
 +#endif
 +    QTest::newRow("executable") << exePath << executableType;
 +}
 +
 +void KMimeTypeTest::testFindByPathUsingFileName()
 +{
 +    QFETCH(QString, fileName);
 +    QFETCH(QString, expectedMimeType);
 +    KMimeType::Ptr mime = KMimeType::findByPath(fileName);
 +    QVERIFY( mime );
 +    QCOMPARE(mime->name(), expectedMimeType);
 +
 +}
 +
 +void KMimeTypeTest::testAdditionalGlobs_data()
 +{
 +    // Other globs that are not in shared-mime-info but which users could define \
themselves.  +    QTest::addColumn<QString>("filename");
 +    QTest::addColumn<QString>("pattern");
 +    QTest::addColumn<bool>("expected");
 +
 +    QTest::newRow("one star, match") << "foo.txt" << "*.txt" << true;
 +    QTest::newRow("README*, match") << "README.foo" << "README*" << true;
 +    QTest::newRow("README.*, match") << "README.foo" << "README.*" << true;
 +    QTest::newRow("README.*, no match") << "README" << "README.*" << false;
 +    QTest::newRow("two stars, match") << "andre.ts.001" << "*.ts.0*" << true;
 +    QTest::newRow("two stars, no match") << "andre.ts" << "*.ts.0*" << false;
 +}
 +
 +void KMimeTypeTest::testAdditionalGlobs()
 +{
 +    QFETCH(QString, filename);
 +    QFETCH(QString, pattern);
 +    QFETCH(bool, expected);
 +
 +    QCOMPARE(KMimeTypeRepository::matchFileName(filename, pattern), expected);
 +}
 +
 +// All the simple tests for findByPath are in testFindByPathUsingFileName_data.
 +// In here we do the tests that need some content in a temporary file.
 +void KMimeTypeTest::testFindByPathWithContent()
 +{
 +    KMimeType::Ptr mime;
 +
 +    // Test a real PDF file.
 +    // If we find x-matlab because it starts with '%' then we are not ordering by \
priority.  +    QTemporaryFile tempFile;
 +    QVERIFY(tempFile.open());
 +    QString tempFileName = tempFile.fileName();
 +    tempFile.write("%PDF-");
 +    tempFile.close();
 +    mime = KMimeType::findByPath( tempFileName );
 +    QVERIFY( mime );
 +    QCOMPARE( mime->name(), QString::fromLatin1( "application/pdf" ) );
 +    // fast mode cannot find the mimetype
 +    mime = KMimeType::findByPath( tempFileName, 0, true );
 +    QVERIFY( mime );
 +    QCOMPARE(mime->name(), QString::fromLatin1("application/octet-stream"));
 +
 +    // Test the case where the extension doesn't match the contents: extension wins
 +    {
 +        QTemporaryFile txtTempFile(QDir::tempPath() + \
QLatin1String("/kmimetypetest_XXXXXX.txt"));  +        QVERIFY(txtTempFile.open());
 +        txtTempFile.write("%PDF-");
 +        QString txtTempFileName = txtTempFile.fileName();
 +        txtTempFile.close();
 +        mime = KMimeType::findByPath( txtTempFileName );
 +        QVERIFY( mime );
 +        QCOMPARE( mime->name(), QString::fromLatin1( "text/plain" ) );
 +        // fast mode finds the same
 +        mime = KMimeType::findByPath( txtTempFileName, 0, true );
 +        QVERIFY( mime );
 +        QCOMPARE( mime->name(), QString::fromLatin1( "text/plain" ) );
 +    }
 +
 +    // Now the case where extension differs from contents, but contents has >80 \
                magic rule
-     // XDG spec says: contents wins. But we can't sniff all files...
++    // XDG spec used to say: contents wins. But we can't sniff all files...
++    // XDG spec has now been amended, extensions always win.
 +    {
 +        QTemporaryFile txtTempFile(QDir::tempPath() + \
QLatin1String("/kmimetypetest_XXXXXX.txt"));  +        QVERIFY(txtTempFile.open());
 +        txtTempFile.write("<smil");
 +        QString txtTempFileName = txtTempFile.fileName();
 +        txtTempFile.close();
 +        mime = KMimeType::findByPath( txtTempFileName );
 +        QVERIFY( mime );
 +        QCOMPARE( mime->name(), QString::fromLatin1( "text/plain" ) );
 +    }
 +}
 +
 +void KMimeTypeTest::testFindByUrl()
 +{
 +    // Tests with local files are already done in testFindByPath,
 +    // here we test for remote urls only.
 +    KMimeType::Ptr mime;
 +    mime = KMimeType::findByUrl( KUrl("http://foo/bar.png") );
 +    QVERIFY( mime );
 +
 +    QCOMPARE( mime->name(), QString::fromLatin1( "application/octet-stream" ) ); // \
HTTP can't know before downloading  +
 +    mime = KMimeType::findByUrl(KUrl("http://foo/s0/"));
 +    QCOMPARE( mime->name(), QString::fromLatin1( "application/octet-stream" ) ); // \
HTTP can't know before downloading  +
 +#if 0 // no such logic in QMimeType, we get default mimetype, KRun will figure it \
out  +    if ( !KProtocolInfo::isKnownProtocol(KUrl("man:/")) )
 +        QSKIP_PORTING( "man protocol not installed", SkipSingle );
 +
 +    mime = KMimeType::findByUrl( KUrl("man:/ls") );
 +    QVERIFY( mime );
 +    QCOMPARE( mime->name(), QString::fromLatin1("text/html") );
 +
 +    mime = KMimeType::findByUrl( KUrl("man:/ls/") );
 +    QVERIFY( mime );
 +    QCOMPARE( mime->name(), QString::fromLatin1("text/html") );
 +#endif
 +
 +    mime = KMimeType::findByUrl(KUrl("fish://host/test1")); // like fish does, to \
test for known extensions  +    QVERIFY(mime);
 +    QCOMPARE(mime->name(), QString::fromLatin1("application/octet-stream"));
 +}
 +
 +void KMimeTypeTest::testFindByNameAndContent()
 +{
 +    KMimeType::Ptr mime;
 +
 +    QByteArray textData = "Hello world";
 +    // textfile -> text/plain. No extension -> mimetype is found from the contents.
 +    mime = KMimeType::findByNameAndContent("textfile", textData);
 +    QVERIFY( mime );
 +    QCOMPARE( mime->name(), QString::fromLatin1("text/plain") );
 +
 +    // textfile.foo -> text/plain. Unknown extension -> mimetype is found from the \
contents.  +    mime = KMimeType::findByNameAndContent("textfile.foo", textData);
 +    QVERIFY( mime );
 +    QCOMPARE( mime->name(), QString::fromLatin1("text/plain") );
 +
 +    // textfile.doc -> text/plain. We added this to the mimetype database so that \
it can be handled.  +    mime = KMimeType::findByNameAndContent("textfile.doc", \
textData);  +    QVERIFY( mime );
 +    QCOMPARE( mime->name(), QString::fromLatin1("text/plain") );
 +
 +    // mswordfile.doc -> application/msword. Found by contents, because of the \
above case.  +    // Note that it's application/msword, not application/vnd.ms-word, \
since it's the former that is registered to IANA.  +    QByteArray mswordData = \
"\320\317\021\340\241\261\032\341";  +    mime = \
KMimeType::findByNameAndContent("mswordfile.doc", mswordData);  +    QVERIFY( mime );
 +    if (mime->name() == "application/vnd.ms-word") { // this comes from \
/usr/share/mime/packages/libreoffice.xml....  +        QEXPECT_FAIL("", \
"libreoffice.xml is messing with us", Continue);  +    }
 +    // If you get powerpoint instead, then you're hit by \
https://bugs.freedesktop.org/show_bug.cgi?id=435 - upgrade to shared-mime-info >= \
0.22  +    QCOMPARE( mime->name(), QString::fromLatin1("application/msword") );
 +
 +    // excelfile.xls -> application/vnd.ms-excel. Found by extension.
 +    mime = KMimeType::findByNameAndContent("excelfile.xls", mswordData /*same \
magic*/);  +    QVERIFY( mime );
 +    QCOMPARE( mime->name(), QString::fromLatin1("application/vnd.ms-excel") );
 +
 +    // textfile.xls -> application/vnd.ms-excel. Found by extension. User shouldn't \
rename a text file to .xls ;)  +    mime = \
KMimeType::findByNameAndContent("textfile.xls", textData);  +    QVERIFY( mime );
 +    QCOMPARE( mime->name(), QString::fromLatin1("application/vnd.ms-excel") );
 +
 +#if 0   // needs shared-mime-info >= 0.20
 +    QByteArray tnefData = "\x78\x9f\x3e\x22";
 +    mime = KMimeType::findByNameAndContent("tneffile", mswordData);
 +    QVERIFY( mime );
 +    QCOMPARE( mime->name(), QString::fromLatin1("application/vnd.ms-tnef") );
 +#endif
 +
 +    QByteArray pdfData = "%PDF-";
 +    mime = KMimeType::findByNameAndContent("foo", pdfData);
 +    QVERIFY( mime );
 +    QCOMPARE( mime->name(), QString::fromLatin1("application/pdf") );
 +
 +    // High-priority rule (80)
 +    QByteArray phpData = "<?php";
 +    mime = KMimeType::findByNameAndContent("foo", phpData);
 +    QVERIFY( mime );
 +    QCOMPARE( mime->name(), QString::fromLatin1("application/x-php") );
 +}
 +
 +void KMimeTypeTest::testFindByContent_data()
 +{
 +    QTest::addColumn<QByteArray>("data");
 +    QTest::addColumn<QString>("expectedMimeType");
 +    QTest::newRow("simple text") << QByteArray("Hello world") << "text/plain";
 +    QTest::newRow("html: <html>") << QByteArray("<html>foo</html>") << "text/html";
 +
 +    // fixed in smi-0.30, xml magic has prio 40
 +    QTest::newRow("html: comment+<html>") << \
QByteArray("<!--foo--><html>foo</html>") << "text/html";  +    // \
https://bugs.freedesktop.org/show_bug.cgi?id=11259, fixed in smi-0.22  +    \
QTest::newRow("html: <script>") << QByteArray("<script>foo</script>") << "text/html"; \
+  +    QTest::newRow("pdf") << QByteArray("%PDF-") << "application/pdf";
 +    QTest::newRow("no mimetype known") << QByteArray("\261\032\341\265") << \
"application/octet-stream";  +
 +    QByteArray mswordData = "\320\317\021\340\241\261\032\341";
 +    // same as \xD0\xCF\x11\xE0 \xA1\xB1\x1A\xE1
 +    QVERIFY(KMimeType::isBufferBinaryData(mswordData));
 +    // We have no magic specific to msword data, so finding x-ole-storage is \
correct.  +    // If you get powerpoint instead, then you're hit by \
https://bugs.freedesktop.org/show_bug.cgi?id=435 - upgrade to shared-mime-info >= \
0.22  +    QTest::newRow("msword") << mswordData << "application/x-ole-storage";
 +}
 +
 +void KMimeTypeTest::testFindByContent()
 +{
 +    QFETCH(QByteArray, data);
 +    QFETCH(QString, expectedMimeType);
 +
 +    KMimeType::Ptr mime = KMimeType::findByContent(data);
 +    QVERIFY( mime );
 +    QCOMPARE( mime->name(), expectedMimeType );
 +}
 +
 +void KMimeTypeTest::testFindByFileContent()
 +{
 +    KMimeType::Ptr mime;
 +    int accuracy = 0;
 +
 +    // Calling findByFileContent on a directory
 +    mime = KMimeType::findByFileContent("/", &accuracy);
 +    QVERIFY(mime);
 +    QCOMPARE(mime->name(), QString::fromLatin1("inode/directory"));
 +    QCOMPARE(accuracy, 100);
 +
 +    // Albert calls findByFileContent with a URL instead of a path and gets 11021 \
as accuracy :)  +    // It was not set inside findByFileContent -> fixed.
 +    mime = KMimeType::findByFileContent("file:///etc/passwd" /*bad example code, \
use a path instead*/, &accuracy);  +    QVERIFY(mime);
 +    QCOMPARE(mime->name(), QString::fromLatin1("application/octet-stream"));
 +    QCOMPARE(accuracy, 0);
 +}
 +
 +void KMimeTypeTest::testAllMimeTypes()
 +{
 +    const KMimeType::List lst = KMimeType::allMimeTypes(); // does NOT include \
aliases  +    QVERIFY( !lst.isEmpty() );
 +
 +    for ( KMimeType::List::ConstIterator it = lst.begin();
 +          it != lst.end(); ++it ) {
 +        const KMimeType::Ptr mime = (*it);
 +        const QString name = mime->name();
 +        //qDebug( "%s", qPrintable( name ) );
 +        QVERIFY( !name.isEmpty() );
 +        QCOMPARE( name.count( '/' ), 1 );
 +
 +        const KMimeType::Ptr lookedupMime = KMimeType::mimeType( name );
 +        QVERIFY( lookedupMime ); // not null
 +        if (name != "application/vnd.ms-word" && name != \
"application/x-pkcs7-certificates" && name != "application/x-x509-ca-cert") {  +      \
QCOMPARE( lookedupMime->name(), name );  +            // if this fails, you have an \
alias defined as a real mimetype too!  +            //
 +            // Note: this also happens with x-win-lnk when your kde.xml defines it \
as an alias, while  +            // /usr/share/mime/packages/kde.xml defines it as a \
real mimetype. This is a false positive,  +            // remove one of the kde.xml \
files.  +            //
 +            // It also happens with application/x-pkcs7-certificates due to
 +            // /usr/share/mime/packages/gcr-crypto-types.xml. Remove that file and \
run  +            // `update-mime-database /usr/share/mime`.
 +        }
 +    }
 +}
 +
 +void KMimeTypeTest::testAlias()
 +{
 +    const KMimeType::Ptr canonical = KMimeType::mimeType( "application/xml" );
 +    QVERIFY( canonical );
 +    KMimeType::Ptr alias = KMimeType::mimeType( "text/xml" );
 +    QVERIFY( alias );
 +    QCOMPARE( alias->name(), QString("application/xml") );
 +
 +    QVERIFY(alias->is("application/xml"));
 +    QVERIFY(canonical->is("text/xml"));
 +
 +    // Test for bug 197346: does nspluginscan see that audio/mp3 already exists?
 +    bool mustWriteMimeType = KMimeType::mimeType("audio/mp3").isNull();
 +    QVERIFY(!mustWriteMimeType);
 +}
 +
 +void KMimeTypeTest::testMimeTypeParent()
 +{
 +    // All file-like mimetypes inherit from octet-stream
 +    const KMimeType::Ptr wordperfect = \
KMimeType::mimeType("application/vnd.wordperfect");  +    QVERIFY(wordperfect);
 +    QCOMPARE(wordperfect->parentMimeTypes().join(","), \
QString("application/octet-stream"));  +    \
QVERIFY(wordperfect->is("application/octet-stream"));  +
 +    QVERIFY(KMimeType::mimeType("image/svg+xml-compressed")->is("application/x-gzip"));
  +
 +    // Check that msword derives from ole-storage [it didn't in 0.20, but we added \
it to kde.xml]  +    const KMimeType::Ptr msword = \
KMimeType::mimeType("application/msword");  +    QVERIFY(msword);
 +    const KMimeType::Ptr olestorage = \
KMimeType::mimeType("application/x-ole-storage");  +    QVERIFY(olestorage);
 +    QVERIFY(msword->is(olestorage->name()));
 +    QVERIFY(msword->is("application/octet-stream"));
 +
 +    const KMimeType::Ptr directory = KMimeType::mimeType("inode/directory");
 +    QVERIFY(directory);
 +    QCOMPARE(directory->parentMimeTypes().count(), 0);
 +    QVERIFY(!directory->is("application/octet-stream"));
 +
 +    // Check that text/x-patch knows that it inherits from text/plain (it says so \
explicitly)  +    const KMimeType::Ptr plain = KMimeType::mimeType( "text/plain" );
 +    const KMimeType::Ptr derived = KMimeType::mimeType( "text/x-patch" );
 +    QVERIFY( derived );
 +    QCOMPARE( derived->parentMimeTypes().join(","), plain->name() );
 +    QVERIFY( derived->is("text/plain") );
 +    QVERIFY( derived->is("application/octet-stream") );
 +
 +    // Check that application/x-shellscript inherits from application/x-executable
 +    // (Otherwise KRun cannot start shellscripts...)
 +    // This is a test for multiple inheritance...
 +    const KMimeType::Ptr shellscript = \
KMimeType::mimeType("application/x-shellscript");  +    QVERIFY(shellscript);
 +    QVERIFY(shellscript->is("text/plain"));
 +    QVERIFY(shellscript->is("application/x-executable"));
 +    const QStringList shellParents = shellscript->parentMimeTypes();
 +    QVERIFY(shellParents.contains("text/plain"));
 +    QVERIFY(shellParents.contains("application/x-executable"));
 +    QCOMPARE(shellParents.count(), 2); // only the above two
 +    const QStringList allShellParents = shellscript->allParentMimeTypes();
 +    QVERIFY(allShellParents.contains("text/plain"));
 +    QVERIFY(allShellParents.contains("application/x-executable"));
 +    QVERIFY(allShellParents.contains("application/octet-stream"));
 +    // Must be least-specific last, i.e. breadth first.
 +    QCOMPARE(allShellParents.last(), QString("application/octet-stream"));
 +
 +    // Check that text/x-mrml knows that it inherits from text/plain (implicitly)
 +    const KMimeType::Ptr mrml = KMimeType::mimeType("text/x-mrml");
 +    if (!mrml)
 +        QSKIP_PORTING("kdelibs not installed", SkipAll);
 +    QVERIFY(mrml->is("text/plain"));
 +    QVERIFY(mrml->is("application/octet-stream"));
 +}
 +
 +void KMimeTypeTest::testMimeTypeInheritancePerformance()
 +{
 +    // Check performance of is(). In kde3 the list of mimetypes with previews had \
63 items...  +    // We could get it with \
KServiceTypeTrader::self()->query("ThumbCreator") and the "MimeTypes"  +    // \
property, but this would give variable results and requires other modules installed.  \
+    QStringList mimeTypes; mimeTypes << "image/jpeg" << "image/png" << "image/tiff" \
<< "text/plain" << "text/html";  +    mimeTypes += mimeTypes;
 +    mimeTypes += mimeTypes;
 +    mimeTypes += mimeTypes;
 +    QCOMPARE(mimeTypes.count(), 40);
 +    KMimeType::Ptr mime = KMimeType::mimeType("text/x-chdr");
 +    QVERIFY(mime);
 +    QTime dt; dt.start();
 +    QBENCHMARK {
 +        QString match;
 +        foreach (const QString& mt, mimeTypes) {
 +            if (mime->is(mt)) {
 +                match = mt;
 +                // of course there would normally be a "break" here, but we're \
testing worse-case  +                // performance here
 +            }
 +        }
 +        QCOMPARE(match, QString("text/plain"));
 +    }
 +    // Results on David's machine (April 2009):
 +    // With the KMimeType::is() code that loaded every parent KMimeType:
 +    // 3.5 msec / 7,000,000 ticks / 5,021,498 instr. loads per iteration
 +    // After the QHash for parent mimetypes in ksycoca, removing the need to load \
full mimetypes:  +    // 0.57 msec / 1,115,000 ticks / 938,356 instr. loads per \
iteration  +    // After converting the QMap for aliases into a QHash too:
 +    // 0.48 msec / 960,000 ticks / 791,404 instr. loads per iteration
 +    // July 2010: After moving KMimeType out of ksycoca:
 +    // 0.21 msec / 494,000 ticks / 568,345 instr. loads per iteration
 +}
 +
 +// Helper method for all the trader tests
 +static bool offerListHasService( const KService::List& offers,
 +                                 const QString& entryPath )
 +{
 +    bool found = false;
 +    KService::List::const_iterator it = offers.begin();
 +    for ( ; it != offers.end() ; ++it )
 +    {
 +        if ( (*it)->entryPath() == entryPath ) {
 +            if( found ) { // should be there only once
 +                qWarning( "ERROR: %s was found twice in the list", qPrintable( \
entryPath ) );  +                return false; // make test fail
 +            }
 +            found = true;
 +        }
 +    }
 +    return found;
 +}
 +
 +void KMimeTypeTest::testMimeTypeTraderForTextPlain()
 +{
 +    if ( !KSycoca::isAvailable() )
 +        QSKIP_PORTING( "ksycoca not available", SkipAll );
 +
 +    // Querying mimetype trader for services associated with text/plain
 +    KService::List offers = KMimeTypeTrader::self()->query("text/plain", \
"KParts/ReadOnlyPart");  +    QVERIFY(!offerListHasService(offers, \
"fakepatchpart.desktop"));  +    QVERIFY(offerListHasService(offers, \
"faketextpart.desktop"));  +
 +    offers = KMimeTypeTrader::self()->query("text/plain", "KPluginInfo");
 +    QVERIFY( offers.count() > 0 );
 +
 +    // We should have at least the fake text plugin that we created for this.
 +    // (The actual plugins from kdelibs don't mention text/plain anymore)
 +    QVERIFY( offerListHasService( offers, "faketextplugin.desktop" ) );
 +
 +    // We shouldn't have non-plugins
 +    QVERIFY( !offerListHasService( offers, "fakepatchpart.desktop" ) );
 +    QVERIFY( !offerListHasService( offers, "faketextpart.desktop" ) );
 +}
 +
 +void KMimeTypeTest::testMimeTypeTraderForDerivedMimeType()
 +{
 +    if ( !KSycoca::isAvailable() )
 +        QSKIP_PORTING( "ksycoca not available", SkipAll );
 +
 +    // Querying mimetype trader for services associated with text/x-patch, which \
inherits from text/plain  +    KService::List offers = \
KMimeTypeTrader::self()->query("text/x-patch", "KParts/ReadOnlyPart");  +    QVERIFY( \
offerListHasService( offers, "fakepatchpart.desktop" ) );  +    QVERIFY( \
offerListHasService( offers, "faketextpart.desktop" ) );  +    QVERIFY( \
(*offers.begin())->entryPath() != "faketextpart.desktop" ); // in the list, but not \
preferred  +
 +    offers = KMimeTypeTrader::self()->query("text/x-patch", "KPluginInfo");
 +    QVERIFY( offers.count() > 0 );
 +
 +    // We should have at least the fake text plugin that we created for this.
 +    // (The actual plugins from kdelibs don't mention text/plain anymore)
 +    QVERIFY( offerListHasService( offers, "faketextplugin.desktop" ) );
 +
 +    offers = KMimeTypeTrader::self()->query("text/x-patch", "Application");
 +    QVERIFY( !offerListHasService( offers, "faketextpart.desktop" ) );
 +
 +    // We shouldn't have non-kde apps
 +    Q_FOREACH( KService::Ptr service, offers )
 +        kDebug() << service->name() << service->entryPath();
 +
 +    QVERIFY( !offerListHasService( offers, m_nonKdeApp ) );
 +}
 +
 +void KMimeTypeTest::testPreferredService()
 +{
 +    // The "NotShowIn=KDE" service should not be the preferred one!
 +    KService::Ptr serv = KMimeTypeTrader::self()->preferredService("text/plain");
 +    QVERIFY( serv->entryPath() != m_nonKdeApp );
 +    QCOMPARE(serv->entryPath(), m_textPlainApp);
 +}
 +
 +void KMimeTypeTest::testMimeTypeTraderForAlias()
 +{
 +    if ( !KSycoca::isAvailable() )
 +        QSKIP_PORTING( "ksycoca not available", SkipAll );
 +
 +    const KService::List referenceOffers = \
KMimeTypeTrader::self()->query("application/xml", "KParts/ReadOnlyPart");  +    \
QVERIFY(offerListHasService(referenceOffers, "faketextpart.desktop"));  +    \
QVERIFY(!offerListHasService(referenceOffers, "fakepatchpart.desktop"));  +
 +    // Querying mimetype trader for services associated with text/xml, which is an \
alias for application/xml  +    const KService::List offers = \
KMimeTypeTrader::self()->query("text/xml", "KParts/ReadOnlyPart");  +    \
QVERIFY(offerListHasService(offers, "faketextpart.desktop"));  +    \
QVERIFY(!offerListHasService(offers, "fakepatchpart.desktop"));  +
 +    QCOMPARE(offers.count(), referenceOffers.count());
 +}
 +
 +void KMimeTypeTest::testHasServiceType1() // with services constructed with a full \
path (rare)  +{
 +    QString faketextpartPath = \
QStandardPaths::locate(QStandardPaths::GenericDataLocation, \
QLatin1String("/kde5/services/") + "faketextpart.desktop" );  +    QVERIFY( \
!faketextpartPath.isEmpty() );  +    KService faketextpart( faketextpartPath );
 +    QVERIFY( faketextpart.hasMimeType( "text/plain" ) );
 +    QVERIFY(!faketextpart.hasMimeType("text/x-patch")); // inherited mimetype; \
fails  +    QVERIFY( !faketextpart.hasMimeType( "image/png" ) );
 +    QVERIFY( faketextpart.hasServiceType( "KParts/ReadOnlyPart" ) );
 +    QVERIFY( !faketextpart.hasServiceType( "KParts/ReadWritePart" ) );
 +    QVERIFY( !faketextpart.hasServiceType( "KPluginInfo" ) );
 +
 +    QString textPluginPath = \
QStandardPaths::locate(QStandardPaths::GenericDataLocation, \
QLatin1String("/kde5/services/") + "faketextplugin.desktop" );  +    QVERIFY( \
!textPluginPath.isEmpty() );  +    KService textPlugin( textPluginPath );
 +    QVERIFY( textPlugin.hasServiceType( "KPluginInfo" ) );
 +    QVERIFY( !textPlugin.hasServiceType( "KParts/ReadOnlyPart" ) );
 +}
 +
 +void KMimeTypeTest::testHasServiceType2() // with services coming from ksycoca
 +{
 +    KService::Ptr faketextpart = KService::serviceByDesktopPath( \
"faketextpart.desktop" );  +    QVERIFY( !faketextpart.isNull() );
 +    QVERIFY( faketextpart->hasMimeType( "text/plain" ) );
 +    QVERIFY( faketextpart->hasMimeType( "text/x-patch" ) ); // due to inheritance
 +    QVERIFY( !faketextpart->hasMimeType( "image/png" ) );
 +    QVERIFY( faketextpart->hasServiceType( "KParts/ReadOnlyPart" ) );
 +    QVERIFY( !faketextpart->hasServiceType( "KParts/ReadWritePart" ) );
 +    QVERIFY( !faketextpart->hasServiceType( "KPluginInfo" ) );
 +
 +    KService::Ptr textPlugin= KService::serviceByDesktopPath( \
"faketextplugin.desktop" );  +    QVERIFY( !textPlugin.isNull() );
 +    QVERIFY( textPlugin->hasServiceType( "KPluginInfo" ) );
 +    QVERIFY( !textPlugin->hasServiceType( "KParts/ReadOnlyPart" ) );
 +}
 +
 +void KMimeTypeTest::testPatterns_data()
 +{
 +    QTest::addColumn<QString>("mimeType");
 +    QTest::addColumn<QString>("patterns");
 +    QTest::addColumn<QString>("mainExtension");
 +    QTest::newRow("mimetype with a single pattern") << "application/pdf" << "*.pdf" \
<< ".pdf";  +    QTest::newRow("mimetype with multiple patterns") << \
"application/x-kpresenter" << "*.kpr;*.kpt" << ".kpr";  +    if \
(KMimeType::sharedMimeInfoVersion() > KDE_MAKE_VERSION(0, 60, 0)) {  +        \
QTest::newRow("mimetype with many patterns") << "application/vnd.wordperfect" << \
"*.wp;*.wp4;*.wp5;*.wp6;*.wpd;*.wpp" << ".wp";  +    }
 +    QTest::newRow("oasis text mimetype") << \
"application/vnd.oasis.opendocument.text" << "*.odt" << ".odt";  +    \
QTest::newRow("oasis presentation mimetype") << \
"application/vnd.oasis.opendocument.presentation" << "*.odp" << ".odp";  +    \
QTest::newRow("mimetype with multiple patterns, *.doc added by kde") << "text/plain" \
<< "*.asc;*.txt;*.doc;*,v" << ".txt";  +    QTest::newRow("mimetype with uncommon \
pattern") << "application/x-kcachegrind" << "callgrind.out*;cachegrind.out*" << \
QString();  +    QTest::newRow("mimetype with no patterns") << \
"application/x-ole-storage" << QString() << QString();  +}
 +
 +void KMimeTypeTest::testPatterns()
 +{
 +    QFETCH(QString, mimeType);
 +    QFETCH(QString, patterns);
 +    QFETCH(QString, mainExtension);
 +    KMimeType::Ptr mime = KMimeType::mimeType( mimeType );
 +    QVERIFY(mime);
 +    // Sort both lists; order is unreliable since shared-mime-info uses hashes \
internally.  +    QStringList expectedPatterns = patterns.split(';');
 +    expectedPatterns.sort();
 +    QStringList mimePatterns = mime->patterns();
 +
 +    if (mimeType == "application/vnd.oasis.opendocument.text" && \
mimePatterns.contains("*.fodt")) {  +        QSKIP_PORTING("Skipping test which would \
fail due to an upstream bug, see https://bugs.freedesktop.org/show_bug.cgi?id=31242", \
SkipSingle);  +    }
 +
 +    if (mimeType == "application/vnd.oasis.opendocument.presentation" && \
mimePatterns.contains("*.fodp")) {  +        QSKIP_PORTING("Skipping test which would \
fail due to an upstream bug, see https://bugs.freedesktop.org/show_bug.cgi?id=31242", \
SkipSingle);  +    }
 +
 +    // shared-mime-info 0.30 adds *,v to text/plain, let's add it from this test so \
that it works  +    // with older versions too.
 +    if (mimeType == "text/plain" && !mimePatterns.contains("*,v"))
 +        mimePatterns.append("*,v");
 +    mimePatterns.sort();
 +    QCOMPARE(mimePatterns.join(";"), expectedPatterns.join(";"));
 +
 +    QCOMPARE(mime->mainExtension(), mainExtension);
 +}
 +
 +void KMimeTypeTest::testExtractKnownExtension_data()
 +{
 +    QTest::addColumn<QString>("fileName");
 +    QTest::addColumn<QString>("extension");
 +    QTest::newRow("simple extension") << "foo.pdf" << "pdf";
 +    QTest::newRow("filename has two extensions, last one matches") << \
"kpresenter.foo.kpt" << "kpt";  +    QTest::newRow("filename has two extensions, \
pattern for both exist") << "foo.tar.bz2" << "tar.bz2";  +    QTest::newRow("bz2 \
alone works too") << "foo.bz2" << "bz2";  +}
 +
 +void KMimeTypeTest::testExtractKnownExtension()
 +{
 +    QFETCH(QString, fileName);
 +    QFETCH(QString, extension);
 +    QCOMPARE(KMimeType::extractKnownExtension(fileName), extension);
 +}
 +
 +struct LessMimeType_ByComment
 +{
 +    bool operator()(const KMimeType::Ptr& lhs, const KMimeType::Ptr& rhs) const
 +    {
 +        return lhs->comment() < rhs->comment();
 +    }
 +};
 +
 +void KMimeTypeTest::testSortByComment()
 +{
 +    QBENCHMARK {
 +        KMimeType::List sortedList = KMimeType::allMimeTypes();
 +        qSort( sortedList.begin(), sortedList.end(), LessMimeType_ByComment() );
 +    }
 +}
 +
 +void KMimeTypeTest::testFromThread()
 +{
 +    // Some simple tests to test more API from testThreads without using _data()
 +    KMimeType::Ptr mime = KMimeType::mimeType("application/pdf");
 +    QVERIFY(mime);
 +    QCOMPARE(mime->mainExtension(), QString::fromLatin1(".pdf"));
 +}
 +
 +void KMimeTypeTest::testThreads()
 +{
 +    QThreadPool::globalInstance()->setMaxThreadCount(20);
 +    // Note that data-based tests cannot be used here (QTest::fetchData asserts).
 +    QList<QFuture<void> > futures;
 +    futures << QtConcurrent::run(this, &KMimeTypeTest::testFindByUrl);
 +    futures << QtConcurrent::run(this, &KMimeTypeTest::testFindByFileContent);
 +    futures << QtConcurrent::run(this, &KMimeTypeTest::testFindByNameAndContent);
 +    futures << QtConcurrent::run(this, &KMimeTypeTest::testFindByPathWithContent);
 +    futures << QtConcurrent::run(this, &KMimeTypeTest::testAllMimeTypes);
 +    futures << QtConcurrent::run(this, &KMimeTypeTest::testAlias);
 +    futures << QtConcurrent::run(this, &KMimeTypeTest::testMimeTypeParent);
 +    futures << QtConcurrent::run(this, &KMimeTypeTest::testPreferredService);
 +    futures << QtConcurrent::run(this, &KMimeTypeTest::testFromThread);
 +    kDebug() << "Joining all threads";
 +    Q_FOREACH(QFuture<void> f, futures) // krazy:exclude=foreach
 +        f.waitForFinished();
 +}
 +
 +#include "kmimetypetest.moc"
diff --cc staging/kservice/src/services/kservicetypetrader.h
index 72cb84d,0000000..64c6110
mode 100644,000000..100644
--- a/staging/kservice/src/services/kservicetypetrader.h
+++ b/staging/kservice/src/services/kservicetypetrader.h
@@@ -1,218 -1,0 +1,218 @@@
 +/* This file is part of the KDE libraries
 +   Copyright (C) 2000 Torben Weis <weis@kde.org>
 +   Copyright (C) 2006 David Faure <faure@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 version 2 as published by the Free Software Foundation.
 +
 +   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.
 +*/
 +#ifndef __kservicetypetrader_h__
 +#define __kservicetypetrader_h__
 +
 +#include "kservice.h"
 +
 +/**
 + * KDE's trader interface (similar to the CORBA Trader), which provides a way
 + * to query the KDE infrastructure for specific applications or components.
 + *
 + * Basically, KServiceTypeTrader provides a way for an application to query
 + * all KDE services (that is, applications, components, plugins) that match
 + * a specific set of requirements. This allows to find specific services
 + * at run-time without having to hard-code their names and/or paths.
 + *
 + * For anything relating to mimetypes (type of files), ignore KServiceTypeTrader
 + * and use KMimeTypeTrader instead.
 + *
 + * \par Example
 + *
 + * If you want to find all plugins for your application,
 + * you would define a KMyApp/Plugin servicetype, and then you can query
 + * the trader for it:
 + * \code
 + * KService::List offers =
 + *     KServiceTypeTrader::self()->query("KMyApp/Plugin");
 + * \endcode
 + *
 + * You can add a constraint in the "trader query language". For instance:
 + * \code
 + * KServiceTypeTrader::self()->query("KMyApp/Plugin",
 + *                                   "[X-KMyApp-InterfaceVersion] > 15");
 + * \endcode
 + *
 + * Please note that when including property names containing arithmetic operators \
like - or +, then you have  + * to put brackets around the property name, in order to \
correctly separate arithmetic operations from  + * the name. So for example a \
constraint expression like  + * \code
 + * X-KMyApp-InterfaceVersion > 4 // wrong!
 + * \endcode
 + * needs to be written as
 + * \code
 + * [X-KMyApp-InterfaceVersion] > 4
 + * \endcode
 + * otherwise it could also be interpreted as
 + * Subtract the numeric value of the property "KMyApp" and "InterfaceVersion" from \
the  + * property "X" and make sure it is greater than 4.\n
 + * Instead of the other meaning, make sure that the numeric value of \
"X-KMyApp-InterfaceVersion" is  + * greater than 4.
 + *
 + * @see KMimeTypeTrader, KService
 + */
 +class KSERVICE_EXPORT KServiceTypeTrader
 +{
 +public:
 +    /**
 +     * Standard destructor
 +     */
 +    ~KServiceTypeTrader();
 +
 +    /**
 +     * The main function in the KServiceTypeTrader class.
 +     *
 +     * It will return a list of services that match your
 +     * specifications.  The only required parameter is the service
 +     * type.  This is something like 'text/plain' or 'text/html'.  The
 +     * constraint parameter is used to limit the possible choices
 +     * returned based on the constraints you give it.
 +     *
 +     * The @p constraint language is rather full.  The most common
 +     * keywords are AND, OR, NOT, IN, and EXIST, all used in an
 +     * almost spoken-word form.  An example is:
 +     * \code
 +     * (Type == 'Service') and (('KParts/ReadOnlyPart' in ServiceTypes) or (exist \
Exec))  +     * \endcode
 +     *
 +     * The keys used in the query (Type, ServiceType, Exec) are all
 +     * fields found in the .desktop files.
 +     *
 +     * @param servicetype A service type like 'KMyApp/Plugin' or 'KFilePlugin'.
 +     * @param constraint  A constraint to limit the choices returned, QString() to
 +     *                    get all services of the given @p servicetype
 +     *
 +     * @return A list of services that satisfy the query
 +     * @see http://techbase.kde.org/Development/Tutorials/Services/Traders#The_KTrader_Query_Language
  +     */
 +    KService::List query( const QString& servicetype,
 +                          const QString& constraint = QString() ) const;
 +
 +    /**
 +     * Returns all offers associated with a given servicetype, IGNORING the
 +     * user preference. The sorting will be the one coming from the \
InitialPreference  +     * in the .desktop files, and services disabled by the user \
will still be listed here.  +     * This is used for "Revert to defaults" buttons in \
GUIs.  +     */
 +    KService::List defaultOffers( const QString& serviceType,
 +                                  const QString& constraint = QString() ) const;
 +    /**
 +     * Returns the preferred service for @p serviceType.
 +     *
 +     * @param serviceType the service type (e.g. "KMyApp/Plugin")
 +     * @return the preferred service, or 0 if no service is available
 +     */
 +    KService::Ptr preferredService( const QString & serviceType ) const;
 +
 +    /**
 +     * This is a static pointer to the KServiceTypeTrader singleton.
 +     *
 +     * You will need to use this to access the KServiceTypeTrader functionality \
since the  +     * constructors are protected.
 +     *
 +     * @return Static KServiceTypeTrader instance
 +     */
 +    static KServiceTypeTrader* self();
 +
 +    /**
 +     * Get a plugin from a trader query
 +     *
 +     * Example:
 +     * \code
 +     * KMyAppPlugin* plugin = \
KServiceTypeTrader::createInstanceFromQuery<KMyAppPlugin>( serviceType, QString(), \
parentObject );  +     * if ( plugin ) {
 +     *     ....
 +     * }
 +     * \endcode
 +     *
 +     * @param serviceType the type of service for which to find a plugin
 +     * @param constraint an optional constraint to pass to the trader (see KTrader)
 +     * @param parent the parent object for the part itself
 +     * @param args A list of arguments passed to the service component
 +     * @param error The string passed here will contain an error description.
 +     * @return A pointer to the newly created object or a null pointer if the
 +     *         factory was unable to create an object of the given type.
 +     */
 +    template <class T>
 +    static T *createInstanceFromQuery(const QString &serviceType,
 +            const QString &constraint = QString(), QObject *parent = 0,
 +            const QVariantList &args = QVariantList(), QString *error = 0)
 +    {
 +        return createInstanceFromQuery<T>(serviceType, 0, parent, constraint, args, \
error);  +    }
 +
 +    /**
 +     * Get a plugin from a trader query
 +     *
 +     * This method works like
 +     * createInstanceFromQuery(const QString&, const QString&, QObject*, const \
QVariantList&, QString*),  +     * but you can specify an additional parent widget.  \
This is important for  +     * a KPart, for example.
 +     *
 +     * @param serviceType the type of service for which to find a plugin
 +     * @param parentWidget the parent widget for the plugin
 +     * @param parent the parent object for the part itself
 +     * @param constraint an optional constraint to pass to the trader (see KTrader)
 +     * @param args A list of arguments passed to the service component
 +     * @param error The string passed here will contain an error description.
 +     * @return A pointer to the newly created object or a null pointer if the
 +     *         factory was unable to create an object of the given type.
 +     */
 +    template <class T>
 +    static T *createInstanceFromQuery(const QString &serviceType,
 +            QWidget *parentWidget, QObject *parent, const QString &constraint = \
QString(),  +            const QVariantList &args = QVariantList(), QString *error = \
0)  +    {
 +        const KService::List offers = self()->query(serviceType, constraint);
++        if (error)
++            error->clear();
 +        Q_FOREACH (const KService::Ptr &ptr, offers) {
 +            T *component = ptr->template createInstance<T>(parentWidget, parent, \
args, error);  +            if (component) {
-                 if (error)
-                     error->clear();
 +                return component;
 +            }
 +        }
-         if (error)
++        if (error && error->isEmpty())
 +            *error = QCoreApplication::translate("", "No service matching the \
requirements was found");  +        return 0;
 +    }
 +
 +    /**
 +     * @internal  (public for KMimeTypeTrader)
 +     */
 +    static void applyConstraints( KService::List& lst,
 +                                  const QString& constraint );
 +
 +private:
 +    /**
 +     * @internal
 +     */
 +    KServiceTypeTrader();
 +
 +    // dissalow copy ctor and assignment operator
 +    KServiceTypeTrader( const KServiceTypeTrader& other );
 +    KServiceTypeTrader& operator=( const KServiceTypeTrader& rhs );
 +
 +    class Private;
 +    Private * const d;
 +
 +    friend class KServiceTypeTraderSingleton;
 +};
 +
 +#endif


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic