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