Difference between revisions of "Development/Architecture/KDE3/MIME Types"

Jump to: navigation, search
(syntax)
m (Text replace - "</code>" to "</syntaxhighlight>")
 
(4 intermediate revisions by 3 users not shown)
Line 29: Line 29:
 
general, there is a certain speed/reliability trade-off you have to make. You  
 
general, there is a certain speed/reliability trade-off you have to make. You  
 
can find out the type of a file by examining only its file name (i.e. in most  
 
can find out the type of a file by examining only its file name (i.e. in most  
cases the file name extension). For example, a file <tt>foo.jpg</tt> is normally  
+
cases the file name extension). For example, a file {{path|foo.jpg}} is normally  
 
"image/jpeg". In cases where the extension is stripped off this is not safe, and  
 
"image/jpeg". In cases where the extension is stripped off this is not safe, and  
 
you actually  have to look at the contents of the file. This is of course slower,  
 
you actually  have to look at the contents of the file. This is of course slower,  
Line 41: Line 41:
  
 
Let us define a type "application/vnd.kde.foo" for our new foobar
 
Let us define a type "application/vnd.kde.foo" for our new foobar
program. To this end, you have to write a file {{file|vnd.kde.foo.desktop}} and
+
program. To this end, you have to write a file {{path|vnd.kde.foo.desktop}} and
 
install it into {{path|KDEDIR/share/mimelnk/application}}. (This is
 
install it into {{path|KDEDIR/share/mimelnk/application}}. (This is
 
the usual location, which may differ between distributions). This can
 
the usual location, which may differ between distributions). This can
Line 50: Line 50:
 
  EXTRA_DIST = $(mime_DATA)
 
  EXTRA_DIST = $(mime_DATA)
  
The file {{file|foo.desktop}} should look as follows:
+
The file {{path|foo.desktop}} should look as follows:
  
<code ini>
+
<syntaxhighlight lang="ini">
 
[Desktop Entry]
 
[Desktop Entry]
 
Type=MimeType
 
Type=MimeType
Line 61: Line 61:
 
Comment=Foo Data File
 
Comment=Foo Data File
 
Comment[de]=Foo Datei
 
Comment[de]=Foo Datei
</code>
+
</syntaxhighlight>
  
 
The "Comment" is entry is supposed to be translated. Since the {{path|.desktop}}
 
The "Comment" is entry is supposed to be translated. Since the {{path|.desktop}}
Line 71: Line 71:
 
Use this like in the following example:
 
Use this like in the following example:
  
<code cppqt3>
+
<syntaxhighlight lang="cpp-qt">
 
KMimeType::Ptr type = KMimeType::mimeType("application/vnd.kde.foo");
 
KMimeType::Ptr type = KMimeType::mimeType("application/vnd.kde.foo");
 
kdDebug() << "Type:    " << type->name() << endl;
 
kdDebug() << "Type:    " << type->name() << endl;
Line 80: Line 80:
 
for (it = patterns.begin(); it != patterns.end(); ++it)
 
for (it = patterns.begin(); it != patterns.end(); ++it)
 
   kdDebug() << "Pattern: " << (*it) << endl;
 
   kdDebug() << "Pattern: " << (*it) << endl;
</code>
+
</syntaxhighlight>
  
 
Last not least you should register your new MIME type with [http://www.iana.org/ IANA].
 
Last not least you should register your new MIME type with [http://www.iana.org/ IANA].
Line 97: Line 97:
 
which indicates a failure to find out the type.
 
which indicates a failure to find out the type.
  
<code cppqt3>
+
<syntaxhighlight lang="cpp-qt">
 
KMimeType::Ptr type = KMimeType::findByURL("/home/user/foobar.jpg");
 
KMimeType::Ptr type = KMimeType::findByURL("/home/user/foobar.jpg");
 
if (type->name() == KMimeType::defaultMimeType())
 
if (type->name() == KMimeType::defaultMimeType())
Line 103: Line 103:
 
else
 
else
 
   kdDebug() << "Type: " << type->name() << endl;
 
   kdDebug() << "Type: " << type->name() << endl;
</code>
+
</syntaxhighlight>
  
 
(this method has some more arguments, but these are undocumented, so simply
 
(this method has some more arguments, but these are undocumented, so simply
Line 114: Line 114:
 
class, which has different error handling:
 
class, which has different error handling:
  
<code cppqt3>
+
<syntaxhighlight lang="cpp-qt">
 
KMimeMagicResult *result =
 
KMimeMagicResult *result =
 
     KMimeMagic::self()->findFileType("/home/user/foobar.jpg");
 
     KMimeMagic::self()->findFileType("/home/user/foobar.jpg");
Line 121: Line 121:
 
else
 
else
 
   kdDebug() << "Type: " << result->mimeType() << endl;
 
   kdDebug() << "Type: " << result->mimeType() << endl;
</code>
+
</syntaxhighlight>
  
 
As a variant of this function, you can also determine the type of a memory
 
As a variant of this function, you can also determine the type of a memory
Line 127: Line 127:
 
mode:
 
mode:
  
<code cppqt3>
+
<syntaxhighlight lang="cpp-qt">
 
QByteArray array;
 
QByteArray array;
 
//...
 
//...
Line 135: Line 135:
 
else
 
else
 
   kdDebug() << "Type: " << res->mimeType() << endl;
 
   kdDebug() << "Type: " << res->mimeType() << endl;
</code>
+
</syntaxhighlight>
  
 
Of course, even KMimeMagic is only able to determine a file type from the
 
Of course, even KMimeMagic is only able to determine a file type from the
 
contents of a local file. For remote files, there is a further possibility:
 
contents of a local file. For remote files, there is a further possibility:
  
<code cppqt3>
+
<syntaxhighlight lang="cpp-qt">
 
KURL url("http://developer.kde.org/favicon.ico");
 
KURL url("http://developer.kde.org/favicon.ico");
 
QString type = KIO::NetAccess::mimetype(url);
 
QString type = KIO::NetAccess::mimetype(url);
Line 147: Line 147:
 
else
 
else
 
   kdDebug() << "Type: " << type << endl;
 
   kdDebug() << "Type: " << type << endl;
</code>
+
</syntaxhighlight>
  
 
This starts a KIO job to download a part of the file and check this.
 
This starts a KIO job to download a part of the file and check this.
Line 157: Line 157:
 
explicitly start the KIO job and connect to some of its signals:
 
explicitly start the KIO job and connect to some of its signals:
  
<code cppqt3>
+
<syntaxhighlight lang="cpp-qt">
 
void FooClass::findType()
 
void FooClass::findType()
 
{
 
{
Line 174: Line 174:
 
               << ((KIO::MimetypeJob *)job)->mimetype() << endl;
 
               << ((KIO::MimetypeJob *)job)->mimetype() << endl;
 
}
 
}
</code>
+
</syntaxhighlight>
  
 
== Mapping a MIME type to an application or service ==
 
== Mapping a MIME type to an application or service ==
Line 185: Line 185:
 
KServiceTypeProfile:  
 
KServiceTypeProfile:  
  
<code cppqt3>
+
<syntaxhighlight lang="cpp-qt">
 
KService::OfferList offers =
 
KService::OfferList offers =
 
     KServiceTypeProfile::offers("text/html", "Application");
 
     KServiceTypeProfile::offers("text/html", "Application");
Line 193: Line 193:
 
   kdDebug() << "Name: " << service->name() << endl;
 
   kdDebug() << "Name: " << service->name() << endl;
 
}
 
}
</code>
+
</syntaxhighlight>
  
 
The return value of this function is a list of service offers. A  
 
The return value of this function is a list of service offers. A  
Line 212: Line 212:
 
function which gives you only the service offer with the highest preference:
 
function which gives you only the service offer with the highest preference:
  
<code cppqt3>
+
<syntaxhighlight lang="cpp-qt">
 
KService::Ptr offer =
 
KService::Ptr offer =
 
   KServiceTypeProfile::preferredService("text/html", "Application");
 
   KServiceTypeProfile::preferredService("text/html", "Application");
Line 219: Line 219:
 
else
 
else
 
   kdDebug() << "No appropriate service found" << endl;
 
   kdDebug() << "No appropriate service found" << endl;
</code>
+
</syntaxhighlight>
  
 
For even more complex queries, there is a full-blown CORBA-like
 
For even more complex queries, there is a full-blown CORBA-like
Line 227: Line 227:
 
[http://api.kde.org/3.5-api/kdelibs-apidocs/kio/kio/html/classKRun.html KRun]:
 
[http://api.kde.org/3.5-api/kdelibs-apidocs/kio/kio/html/classKRun.html KRun]:
  
<code cppqt3>
+
<syntaxhighlight lang="cpp-qt">
 
KURL::List urlList;
 
KURL::List urlList;
 
urlList << "http://www.ietf.org/rfc/rfc1341.txt?number=1341";
 
urlList << "http://www.ietf.org/rfc/rfc1341.txt?number=1341";
 
urlList << "http://www.ietf.org/rfc/rfc2046.txt?number=2046";
 
urlList << "http://www.ietf.org/rfc/rfc2046.txt?number=2046";
 
KRun::run(offer.service(), urlList);
 
KRun::run(offer.service(), urlList);
</code>
+
</syntaxhighlight>
  
 
== Miscellaneous ==
 
== Miscellaneous ==
Line 242: Line 242:
 
and returns the associated icon.
 
and returns the associated icon.
  
<code cppqt3>
+
<syntaxhighlight lang="cpp-qt">
 
KURL url("ftp://ftp.kde.org/pub/incoming/wibble.c");
 
KURL url("ftp://ftp.kde.org/pub/incoming/wibble.c");
 
QString icon = KMimeType::iconForURL(url);
 
QString icon = KMimeType::iconForURL(url);
</code>
+
</syntaxhighlight>
  
 
Running a URL. This looks for the type of the URL and starts the
 
Running a URL. This looks for the type of the URL and starts the
 
user's preferred program associated with this type.
 
user's preferred program associated with this type.
  
<code cppqt3>
+
<syntaxhighlight lang="cpp-qt">
 
KURL url("http://dot.kde.org");
 
KURL url("http://dot.kde.org");
 
new KRun(url);
 
new KRun(url);
</code>
+
</syntaxhighlight>
  
  

Latest revision as of 21:49, 29 June 2011

KDE Architecture - MIME type handling

Contents

[edit] What are MIME types?

MIME types are used to describe the content type of files or data chunks. Originally they were introduced in order to allow sending around image or sound files etc. by e-mail (MIME stands for "Multipurpose Internet Mail Extensions"). Later this system was also used by web browsers to determine how to present data sent by a web server to the user. For example, an HTML page has a MIME type "text/html", a postscript file "application/postscript". In KDE, this concept is used at a variety of places:

  • In Konqueror's icon view, files are represented by icons. Each MIME type has a certain associated icon shown here.
  • When you click onto a file icon or a file name in Konqueror, either the file is shown in an embedded view, or an application associated with the file type is opened.
  • When you drag and drop some data from one application to another (or within the same application), the drop target may choose to accept only certain data types. Furthermore, it will handle image data different from textual data.
  • Clipboard data has a MIME type. Traditionally, X programs only handle pixmaps or texts, but with Qt, there are no restrictions on the data type.

From the above examples, it is clear that MIME handling is a complex issue. First, it is necessary to establish a mapping from file names to MIME types. KDE goes one step further in allowing even file contents to be mapped to MIME types, for cases in which the file name is not available. Second, it is necessary to map MIME types to applications or libraries which can view or edit a file with a certain type, or create a thumbnail picture for it.

There is a variety of APIs to figure out the MIME type of data or files. In general, there is a certain speed/reliability trade-off you have to make. You can find out the type of a file by examining only its file name (i.e. in most cases the file name extension). For example, a file foo.jpg is normally "image/jpeg". In cases where the extension is stripped off this is not safe, and you actually have to look at the contents of the file. This is of course slower, in particular for files that have to be downloaded via HTTP first. The content-based method is based on the file KDEDIR/share/mimelnk/magic and therefore difficult to extend. But in general, MIME type information can easily be made available to the system by installing a .desktop file, and it is efficiently and conveniently available through the KDE libraries.

[edit] Defining MIME types

Let us define a type "application/vnd.kde.foo" for our new foobar program. To this end, you have to write a file vnd.kde.foo.desktop and install it into KDEDIR/share/mimelnk/application. (This is the usual location, which may differ between distributions). This can be done by adding this to the Makefile.am:

mimedir = $(kde_mimedir)/application
mime_DATA = vnd.kde.foo.desktop
EXTRA_DIST = $(mime_DATA)

The file foo.desktop should look as follows:

[Desktop Entry]
Type=MimeType
MimeType=application/vnd.kde.foo
Icon=fooicon
Patterns=*.foo;
DefaultApp=foobar
Comment=Foo Data File
Comment[de]=Foo Datei

The "Comment" is entry is supposed to be translated. Since the .desktop file specifies an icon, you should also install an icon fooicon.png, which represents the file e.g. in Konqueror.

In the KDE libraries, such a type definition is mapped to an instance of the class KMimeType. Use this like in the following example:

KMimeType::Ptr type = KMimeType::mimeType("application/vnd.kde.foo");
kdDebug() << "Type:    " << type->name() << endl;
kdDebug() << "Icon:    " << type->icon() << endl;
kdDebug() << "Comment: " << type->comment() << endl;
QStringList patterns = type->patterns();
QStringList::ConstIterator it;
for (it = patterns.begin(); it != patterns.end(); ++it)
  kdDebug() << "Pattern: " << (*it) << endl;

Last not least you should register your new MIME type with IANA. Please contact Marc Mutz for help on this.

[edit] Finding out the MIME type of data

The fast method for finding out the type of a file is KMimeType::findByURL(). This looks for the url string and in most cases determines the type from the extension. For certain protocols (e.g. http, man, info), this mechanism is not used. For example, CGI scripts on web servers written in Perl often have the extension .pl, which would indicate a "text/x-perl" type. However, we file delivered by the server is the output of this script, which is normally HTML. For such a case, KMimeType::findByURL() returns the MIME type "application/octet-stream" (available through KMimeType::defaultMimeType()), which indicates a failure to find out the type.

KMimeType::Ptr type = KMimeType::findByURL("/home/user/foobar.jpg");
if (type->name() == KMimeType::defaultMimeType())
  kdDebug() << "Could not find out type" << endl;
else
  kdDebug() << "Type: " << type->name() << endl;

(this method has some more arguments, but these are undocumented, so simply forget about them.)

You may want to find out a MIME from the contents of file instead of the file name. This is more reliable, but also slower, as it requires reading a part of the file. This is done with the KMimeMagic class, which has different error handling:

KMimeMagicResult *result =
    KMimeMagic::self()->findFileType("/home/user/foobar.jpg");
if (!result || !result->isValid())
  kdDebug() << "Could not find out type" << endl;
else
  kdDebug() << "Type: " << result->mimeType() << endl;

As a variant of this function, you can also determine the type of a memory chunk. This is e.g. used in KWrite in order to find out the highlighting mode:

QByteArray array;
//...
KMimeMagicResult *res = KMimeMagic::self()->findBufferType(array);
if (!res || !res->isValid())
  kdDebug() << "Could not find out type" << endl;
else
  kdDebug() << "Type: " << res->mimeType() << endl;

Of course, even KMimeMagic is only able to determine a file type from the contents of a local file. For remote files, there is a further possibility:

KURL url("http://developer.kde.org/favicon.ico");
QString type = KIO::NetAccess::mimetype(url);
if (type == KMimeType::defaultMimeType())
  kdDebug() << "Could not find out type" << endl;
else
  kdDebug() << "Type: " << type << endl;

This starts a KIO job to download a part of the file and check this. Note that this function is perhaps quite slow and blocks the program. Normally you will only want to use this if KMimeType::findByURL() has returned "application/octet-stream".

On the other hand, if you do not want to block your application, you can also explicitly start the KIO job and connect to some of its signals:

void FooClass::findType()
{
  KURL url("http://developer.kde.org/favicon.ico");
  KIO::MimetypeJob *job = KIO::mimetype(url);
  connect(job, SIGNAL(result(KIO::Job*)),
          this, SLOT(mimeResult(KIO::Job*)));
}
 
void FooClass::mimeResult(KIO::Job *job)
{
  if (job->error())
    job->showErrorDialog();
  else
    kdDebug() << "MIME type: "
              << ((KIO::MimetypeJob *)job)->mimetype() << endl;
}

[edit] Mapping a MIME type to an application or service

When an application is installed, it installs a .desktop file which contains a list of MIME types this application can load. Similarly, components like KParts make this information available by their service .desktop files. So in general, there are several programs and components which can process a given MIME type. You can obtain such a list from the class KServiceTypeProfile:

KService::OfferList offers =
    KServiceTypeProfile::offers("text/html", "Application");
KService::OfferList::ConstIterator it;
for (it = offers.begin(); it != offers.end(); ++it) {
  KService::Ptr service = (*it);
  kdDebug() << "Name: " << service->name() << endl;
}

The return value of this function is a list of service offers. A KServiceOffer packages a KService::Ptr together with a preference number. The list returned by KServiceTypeProfile::offers() is ordered by the user's preference. The user can change this by calling "keditfiletype text/html" or choosing "Edit File Type" on Konqueror's context menu on a HTML file.

In the above example, an offer list of the applications supporting text/html was requested. This will - among others - contain HTML editors like Quanta Plus. You can also replace the second argument "Application" by "KParts::ReadOnlyPart". In that case, you get a list of embedabble components for presenting HTML content, for example KHTML.

In most cases, you are not interested in the list of all service offers for a combination of MIME type and service type. There is a convenience function which gives you only the service offer with the highest preference:

KService::Ptr offer =
  KServiceTypeProfile::preferredService("text/html", "Application");
if (offer)
  kdDebug() << "Name: " << service->name() << endl;
else
  kdDebug() << "No appropriate service found" << endl;

For even more complex queries, there is a full-blown CORBA-like trader.

In order to run an application service with some urls, use KRun:

KURL::List urlList;
urlList << "http://www.ietf.org/rfc/rfc1341.txt?number=1341";
urlList << "http://www.ietf.org/rfc/rfc2046.txt?number=2046";
KRun::run(offer.service(), urlList);

[edit] Miscellaneous

In this section, we want to list some APIs which are loosely related to the previous discussion.

Getting an icon for a URL. This looks for the type of the URL and returns the associated icon.

KURL url("ftp://ftp.kde.org/pub/incoming/wibble.c");
QString icon = KMimeType::iconForURL(url);

Running a URL. This looks for the type of the URL and starts the user's preferred program associated with this type.

KURL url("http://dot.kde.org");
new KRun(url);


Initial Author: Bernd Gehrmann


This page was last modified on 29 June 2011, at 21:49. This page has been accessed 4,649 times. Content is available under Creative Commons License SA 3.0 as well as the GNU Free Documentation License 1.2.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V.Legal