Mime-typer

Hvad er Mime-typer?

Mime-typer bruges til at beskrive type af indhold for filer eller datafragmenter. Oprindeligt indførtes de for at tillade at billeder eller lydfiler, osv. kunne sendes med e-mail (Mime betyder "Multipurpose Internet Mail Extensions"). Senere blev systemet også brugt af browsere for at afgøre hvordan data som sendtes af en web-server skulle vises for brugeren. En HTML-side har for eksempel Mime-typen "text/html", og en Postscript-fil "application/postscript". I KDE bruges denne ide mange forskellige steder:

  • I Konqueror's ikonvisning, repræsenteres filer af ikoner. Hver Mime-type har en vis ikon som den hører sammen med, som vises her.

  • Når man klikker på en filikon eller et filnavn i Konqueror, så vises filen enten i en indlejret visning, eller også startes et program som hører sammen med filtypen.

  • Når du trækker og slipper nogle data fra et program til et andet (eller indenfor samme program), kan målet vælge kun at acceptere visse datatyper. Desuden håndteres billeddata på en anden måde end tekstdata.

  • Data på klippebordet har en Mime-type. Traditionelt håndterede X-programmer kun pixmaps eller tekst, men med Qt er der ingen begrænsning af datatypen.

Det er klart fra ovenstående eksempel, at Mime-håndtering er en kompleks ting. Først skal en tildeling af filnavne til Mime-typer gøres. KDE går yderligere et skridt, og lader til og med filindhold tildeles Mime-typer, i de tilfælde hvor filnavnet ikke er tilgængeligt. Derefter skal Mime-typer tildeles programmer eller biblioteker som kan vise eller redigere en fil af en vis type, eller oprette et miniature af den.

Der er en mængde forskellige programmeringsgrænseflader til at regne ud hvad Mime-typen for data eller filer er. Generelt skal man gøre en afvejning mellem hastighed og tilforladelighed. Man kan finde en filtype ved blot at kigge på filnavnet (i de fleste tilfælde filendelsen). Filen foo.jpg er for eksempel normalt "image/jpeg". I de tilfælde hvor filendelsen er taget væk er dette ikke sikkert, og man skal virkelig kigge i filens indhold. Det er naturligvis langsommere, især for filer som først skal hentes via HTTP. Den indholdsbaserede metode anvender filen KDEDIR/share/mimelnk/magic, og er derfor svær at udvide. Men i almindelighed kan information om Mime-typer let gøres tilgængeligt for systemet, ved at installere en .desktop-fil, og den bliver effektivt og bekvemt tilgængelig via KDE-bibliotekerne.

Definition af Mime-typer

Lad os definere typen "application/x-foo", for vort nye program foobar. For at gøre det, skal filen foo.desktop skrives, og installeres i KDEDIR/share/mimelnk/application. (Det er det sædvanlige sted, som kan variere mellem distributioner). Dette kan gøres ved at tilføje følgende til Makefile.am:

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

Filen foo.desktop skal se ud som følger:

[Desktop Entry]
Type=MimeType
MimeType=application/x-foo
Icon=fooicon
Patterns=*.foo;
DefaultApp=foobar
Comment=Foo Data File
Comment[sv]=Foo-datafil

Indgangen "Comment" er beregnet til at oversættes. Eftersom .desktop-filen angiver en ikon, bør du også installere en ikon fooicon.png, som repræsenterer filen, f.eks. i Konqueror.

I KDE-bibliotekerne svarer en sådan typedefinition til en instans af klassen KMimeType. Brug dette som i følgende eksempel:

KMimeType::Ptr type = KMimeType::mimeType("application/x-foo");
cout << "Type:    " << type->name() < endl;
cout << "Ikon:    " << type->icon() < endl;
cout << "Kommentar: " << type->icon() < endl;
QStringList patterns = type->patterns();
QStringList::ConstIterator it;
for (it = patterns.begin(); it != patterns.end(); ++it)
  cout << "Mønster: " << (*it) << endl;

Afgøre Mime-type for data

Den hurtige måde at afgøre filtypen er KMimeType::findByURL(). Den kigger efter URL'en og afgør i de fleste tilfælde typen ud fra filendelsen. Med visse protokoller (f.eks. http, man, info), bruges denne mekanisme ikke. CGI-scripter på web-servere som skrives i Perl, har for eksempel ofte endelsen .pl, som ville angive typen "text/x-perl". Alligevel er filen som levereres af serveren udskrift fra scriptet, som normalt er HTML. I sådanne tilfælde, returnerer KMimeType::findByURL() Mime-typen "application/octet-stream" (tilgængelig via KMimeType::defaultMimeType()), som angiver at det mislykkedes at finde ud af typen.

KMimeType::Ptr type = KMimeType::findByURL("/home/bernd/foobar.jpg");
if (type->name() == KMimeType::defaultMimeType())
    cout << "Kunne ikke afgøre typen" << endl;
else
    cout << "Type: " << type->name() << endl;

(denne metode har nogle flere argumenter, men disse er ikke dokumenterede, så glem dem hellere helt.)

Man kan ville finde ud af en Mime-type ud fra filens indhold i stedet for filnavnet. Det er tilforladeligere, men også langsommere, eftersom det kræver at en del af filen læses. Det gøres med klassen KMimeMagic, som har en anderledes fejlhåndtering:

KMimeMagicResult *result = KMimeMagic::self()->findFileType("/home/bernd/foobar.jpg");
if (!result || !result->isValid())
    cout << "Kunne ikke afgøre typen" << endl;
else
    cout << "Type: " << result->mimeType() << endl;

Med en variant af denne funktion, kan du også afgøre typen for en hukommelsesstump. Det bruges for eksempel af Kate til at regne fremhævningstilstand ud:

QByteArray array;
...
KMimeMagicResult *result = KMimeMagic::self()->findBufferType(array);
if (!result || !result->isValid())
    cout << "Kunne ikke afgøre typen" << endl;
else
    cout << "Type: " << result->mimeType() << endl;

Naturligvis kan selv KMimeMagic kun afgøre filtypen ud fra indholdet i en lokal fil. For fjernfiler, er der yderligere en mulighed:

KURL url("http://developer.kde.org/favicon.ico");
QString type = KIO::NetAccess::mimetype(url);
if (type == KMimeType::defaultMimeType())
    cout << "Kunne ikke afgøre typen" << endl;
else
    cout << "Type: " << type << endl;

Dette starter et KIO-job til at hente en del af filen, og kontrollere dette. Bemærk at denne funktion måske er rigtig langsom og blokerer programmet. Normalt vil man kun bruge den hvis KMimeType::findByURL() returnerede "application/octet-stream".

På den anden side, hvis du ikke vil blokere programmet, kan du også udtrykkelig starte KIO-jobbet og forbinde til et af dets signaler:

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
        cout << "Mime type: " << ((KIO::MimetypeJob *)job)->mimetype() << endl;
}

Tildel en Mime-type til et program eller tjeneste

Når et program installeres, installerer det en .desktop-fil, som indeholder en liste med MIME-typer som programmet kan indlæse. På samme måde gør komponenter, som en KPart, denne information tilgængelig med deres .desktop-tjenestefiler. Altså er der generelt flere programmer og komponenter som kan behandle en given MIME-type. Du kan skaffe en sådan liste fra klassen 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);
    cout << "Navn: " << service->name() << endl;
}

Returværdien fra funktionen er en liste med tjenesteudbydere. Et KServiceOffer-objekt pakker en KService::Ptr, sammen med et rangrækkefølgenummer. Listen som returneres af KServiceTypeProfile::offers() er ordnet efter hvad brugeren foretrækker. Brugeren kan ændre dette ved at kalde "keditfiletype text/html" eller vælge Redigér filtype i Konqueror's sammenhængsafhængige menu for en HTML-fil.

I eksemplet ovenfor, blev der bedt om en liste med tilbydere af programmer som understøtter text/html. Det omfatter, blandt andet, HTML-editorer såsom Quanta Plus. Du kan også erstatte det andet argument "Application" med "KParts::ReadOnlyPart". I det tilfælde, får du en liste med indlejrbare komponenter til at præsentere HTML-indhold, for eksempel KHTML.

I de fleste tilfælde er du ikke interesseret i listen med alle tilbud om tjenester for en kombination af Mime-type og tjenestetype. Der er en bekvemmelighedsfunktion som kun giver dig de tjenestetilbud som foretrækkes mest:

KService::Ptr offer = KServiceTypeProfile::preferredService("text/html", "Application");
if (offer)
    cout << "Navn: " << service->name() << endl;
else
    cout << "Ingen passende tjeneste fundet" << endl;

For endnu mere komplicerede forespørgsler, er der en fuldstændig CORBA-lignende handler.

For at køre en programtjeneste med nogle URL'er, bruges 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);

Diverse

I dette afsnit giver vi en liste over nogen af de programmeringsgrænseflader som på en eller anden måde hører sammen med den foregående beskrivelse.

Hent en ikon for en URL. Dette kigger efter URL'ens type, og returnerer en tilsvarende ikon.

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

Kør en URL. Dette kigger efter URL'ens type, og starter et tilhørende program til typen som brugeren foretrækker.

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