[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