MIME types (KDE3 Architecture)
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
TDE, 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 TQt, 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. Trinity 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 $TDEDIR/share/mime/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 Trinity libraries.
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 $TDEDIR/share/mime/application. (This is
the usual location, which may differ between distributions). This can
be done by adding something like this to your CMakeLists.txt file:
tde_create_translated_desktop(
SOURCE vnd.kde.foo.desktop
DESTINATION ${MIME_INSTALL_DIR}/application
)
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
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 TDE 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;
TQStringList patterns = type->patterns();
TQStringList::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.
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:
TQByteArray 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");
TQString type = TDEIO::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 TDEIO job and connect to some of its signals:
void FooClass::findType()
{
KURL url("http://trinitydesktop.org/favicon.ico");
TDEIO::MimetypeJob *job = TDEIO::mimetype(url);
connect(job, SIGNAL(result(TDEIO::Job*)),
this, SLOT(mimeResult(TDEIO::Job*)));
}
void FooClass::mimeResult(TDEIO::Job *job)
{
if (job->error())
job->showErrorDialog();
else
kdDebug() << "MIME type: "
<< ((TDEIO::MimetypeJob *)job)->mimetype() << endl;
}
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 TFRHTML.
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);
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");
TQString 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("https://www.trinitydesktop.org");
new KRun(url);
Initial Author: Bernd Gehrmann