kbuildservicetypefactory.cpp

00001 /*  This file is part of the KDE libraries
00002  *  Copyright (C) 1999 David Faure   <faure@kde.org>
00003  *
00004  *  This library is free software; you can redistribute it and/or
00005  *  modify it under the terms of the GNU Library General Public
00006  *  License version 2 as published by the Free Software Foundation;
00007  *
00008  *  This library is distributed in the hope that it will be useful,
00009  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00010  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011  *  Library General Public License for more details.
00012  *
00013  *  You should have received a copy of the GNU Library General Public License
00014  *  along with this library; see the file COPYING.LIB.  If not, write to
00015  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00016  *  Boston, MA 02110-1301, USA.
00017  **/
00018 
00019 #include "kbuildservicetypefactory.h"
00020 #include "ksycoca.h"
00021 #include "ksycocadict.h"
00022 #include "kresourcelist.h"
00023 
00024 #include <kglobal.h>
00025 #include <kstandarddirs.h>
00026 #include <kmessageboxwrapper.h>
00027 #include <kdebug.h>
00028 #include <klocale.h>
00029 #include <assert.h>
00030 #include <kdesktopfile.h>
00031 
00032 template class QDict<KMimeType>;
00033 
00034 KBuildServiceTypeFactory::KBuildServiceTypeFactory() :
00035   KServiceTypeFactory()
00036 {
00037    // Read servicetypes first, since they might be needed to read mimetype properties
00038    m_resourceList = new KSycocaResourceList;
00039    m_resourceList->add("servicetypes", "*.desktop");
00040    m_resourceList->add("servicetypes", "*.kdelnk");
00041    m_resourceList->add( "mime", "*.desktop" );
00042    m_resourceList->add( "mime", "*.kdelnk" );
00043 }
00044 
00045 // return all service types for this factory
00046 // i.e. first arguments to m_resourceList->add() above
00047 QStringList KBuildServiceTypeFactory::resourceTypes()
00048 {
00049     return QStringList() << "servicetypes" << "mime";
00050 }
00051 
00052 KBuildServiceTypeFactory::~KBuildServiceTypeFactory()
00053 {
00054    delete m_resourceList;
00055 }
00056 
00057 KServiceType * KBuildServiceTypeFactory::findServiceTypeByName(const QString &_name)
00058 {
00059    assert (KSycoca::self()->isBuilding());
00060    // We're building a database - the service type must be in memory
00061    KSycocaEntry::Ptr * servType = (*m_entryDict)[ _name ];
00062    if (!servType)
00063       return 0;
00064    return (KServiceType *) ((KSycocaEntry*)*servType);
00065 }
00066 
00067 
00068 KSycocaEntry *
00069 KBuildServiceTypeFactory::createEntry(const QString &file, const char *resource)
00070 {
00071   QString name = file;
00072   int pos = name.findRev('/');
00073   if (pos != -1)
00074   {
00075      name = name.mid(pos+1);
00076   }
00077 
00078   if (name.isEmpty())
00079      return 0;
00080 
00081   KDesktopFile desktopFile(file, true, resource);
00082 
00083   if ( desktopFile.readBoolEntry( "Hidden", false ) == true )
00084       return 0;
00085 
00086   // TODO check Type field first
00087   QString mime = desktopFile.readEntry( "MimeType" );
00088   QString service = desktopFile.readEntry( "X-KDE-ServiceType" );
00089 
00090   if ( mime.isEmpty() && service.isEmpty() )
00091   {
00092     QString tmp = QString("The service/mime type config file\n%1\n"
00093                   "does not contain a ServiceType=...\nor MimeType=... entry").arg( file );
00094     kdWarning(7012) << tmp << endl;
00095     return 0;
00096   }
00097 
00098   KServiceType* e;
00099   if ( mime == "inode/directory" )
00100     e = new KFolderType( &desktopFile );
00101   else if ( mime == "application/x-desktop" )
00102     e = new KDEDesktopMimeType( &desktopFile );
00103   else if ( mime == "application/x-executable" || mime == "application/x-shellscript" )
00104     e = new KExecMimeType( &desktopFile );
00105   else if ( !mime.isEmpty() )
00106     e = new KMimeType( &desktopFile );
00107   else
00108     e = new KServiceType( &desktopFile );
00109 
00110   if (e->isDeleted())
00111   {
00112     delete e;
00113     return 0;
00114   }
00115 
00116   if ( !(e->isValid()) )
00117   {
00118     kdWarning(7012) << "Invalid ServiceType : " << file << endl;
00119     delete e;
00120     return 0;
00121   }
00122 
00123   return e;
00124 }
00125 
00126 void
00127 KBuildServiceTypeFactory::saveHeader(QDataStream &str)
00128 {
00129    KSycocaFactory::saveHeader(str);
00130    str << (Q_INT32) m_fastPatternOffset;
00131    str << (Q_INT32) m_otherPatternOffset;
00132    str << (Q_INT32) m_propertyTypeDict.count();
00133 
00134    QMapIterator<QString, int> it;
00135    for (it = m_propertyTypeDict.begin(); it != m_propertyTypeDict.end(); ++it)
00136    {
00137      str << it.key() << (Q_INT32)it.data();
00138    }
00139 
00140 }
00141 
00142 void
00143 KBuildServiceTypeFactory::save(QDataStream &str)
00144 {
00145    KSycocaFactory::save(str);
00146 
00147    savePatternLists(str);
00148 
00149    int endOfFactoryData = str.device()->at();
00150 
00151    // Update header (pass #3)
00152    saveHeader(str);
00153 
00154    // Seek to end.
00155    str.device()->at(endOfFactoryData);
00156 }
00157 
00158 void
00159 KBuildServiceTypeFactory::savePatternLists(QDataStream &str)
00160 {
00161    // Store each patterns in one of the 2 string lists (for sorting)
00162    QStringList fastPatterns;  // for *.a to *.abcd
00163    QStringList otherPatterns; // for the rest (core.*, *.tar.bz2, *~) ...
00164    QDict<KMimeType> dict;
00165 
00166    // For each mimetype in servicetypeFactory
00167    for(QDictIterator<KSycocaEntry::Ptr> it ( *m_entryDict );
00168        it.current();
00169        ++it)
00170    {
00171       KSycocaEntry *entry = (*it.current());
00172       if ( entry->isType( KST_KMimeType ) )
00173       {
00174         KMimeType *mimeType = (KMimeType *) entry;
00175         QStringList pat = mimeType->patterns();
00176         QStringList::ConstIterator patit = pat.begin();
00177         for ( ; patit != pat.end() ; ++patit )
00178         {
00179            const QString &pattern = *patit;
00180            if ( pattern.findRev('*') == 0
00181                 && pattern.findRev('.') == 1
00182                 && pattern.length() <= 6 )
00183               // it starts with "*.", has no other '*' and no other '.', and is max 6 chars
00184               // => fast patttern
00185               fastPatterns.append( pattern );
00186            else if (!pattern.isEmpty()) // some stupid mimetype files have "Patterns=;"
00187               otherPatterns.append( pattern );
00188            // Assumption : there is only one mimetype for that pattern
00189            // It doesn't really make sense otherwise, anyway.
00190            dict.replace( pattern, mimeType );
00191         }
00192       }
00193    }
00194    // Sort the list - the fast one, useless for the other one
00195    fastPatterns.sort();
00196 
00197    Q_INT32 entrySize = 0;
00198    Q_INT32 nrOfEntries = 0;
00199 
00200    m_fastPatternOffset = str.device()->at();
00201 
00202    // Write out fastPatternHeader (Pass #1)
00203    str.device()->at(m_fastPatternOffset);
00204    str << nrOfEntries;
00205    str << entrySize;
00206 
00207    // For each fast pattern
00208    QStringList::ConstIterator it = fastPatterns.begin();
00209    for ( ; it != fastPatterns.end() ; ++it )
00210    {
00211      int start = str.device()->at();
00212      // Justify to 6 chars with spaces, so that the size remains constant
00213      // in the database file.
00214      QString paddedPattern = (*it).leftJustify(6).right(4); // remove leading "*."
00215      //kdDebug(7021) << QString("FAST : '%1' '%2'").arg(paddedPattern).arg(dict[(*it)]->name()) << endl;
00216      str << paddedPattern;
00217      str << dict[(*it)]->offset();
00218      entrySize = str.device()->at() - start;
00219      nrOfEntries++;
00220    }
00221 
00222    // store position
00223    m_otherPatternOffset = str.device()->at();
00224 
00225    // Write out fastPatternHeader (Pass #2)
00226    str.device()->at(m_fastPatternOffset);
00227    str << nrOfEntries;
00228    str << entrySize;
00229 
00230    // For the other patterns
00231    str.device()->at(m_otherPatternOffset);
00232 
00233    it = otherPatterns.begin();
00234    for ( ; it != otherPatterns.end() ; ++it )
00235    {
00236      //kdDebug(7021) << QString("OTHER : '%1' '%2'").arg(*it).arg(dict[(*it)]->name()) << endl;
00237      str << (*it);
00238      str << dict[(*it)]->offset();
00239    }
00240 
00241    str << QString(""); // end of list marker (has to be a string !)
00242 }
00243 
00244 void
00245 KBuildServiceTypeFactory::addEntry(KSycocaEntry *newEntry, const char *resource)
00246 {
00247    KServiceType * serviceType = (KServiceType *) newEntry;
00248    if ( (*m_entryDict)[ newEntry->name() ] )
00249    {
00250      // Already exists
00251      if (serviceType->desktopEntryPath().endsWith("kdelnk"))
00252         return; // Skip
00253      
00254      // Replace
00255      KSycocaFactory::removeEntry(newEntry);
00256    }
00257    KSycocaFactory::addEntry(newEntry, resource);
00258 
00259 
00260    const QMap<QString,QVariant::Type>& pd = serviceType->propertyDefs();
00261    QMap<QString,QVariant::Type>::ConstIterator pit = pd.begin();
00262    for( ; pit != pd.end(); ++pit )
00263    {
00264      if (!m_propertyTypeDict.contains(pit.key()))
00265        m_propertyTypeDict.insert(pit.key(), pit.data());
00266      else if (m_propertyTypeDict[pit.key()] != pit.data())
00267        kdWarning(7021) << "Property '"<< pit.key() << "' is defined multiple times ("<< serviceType->name() <<")" <<endl;
00268    }
00269 }
00270 
KDE Home | KDE Accessibility Home | Description of Access Keys