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 TQDict<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 TQStringList KBuildServiceTypeFactory::resourceTypes() 00048 { 00049 return TQStringList() << "servicetypes" << "mime"; 00050 } 00051 00052 KBuildServiceTypeFactory::~KBuildServiceTypeFactory() 00053 { 00054 delete m_resourceList; 00055 } 00056 00057 KServiceType * KBuildServiceTypeFactory::findServiceTypeByName(const TQString &_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 TQString &file, const char *resource) 00070 { 00071 TQString 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 TQString mime = desktopFile.readEntry( "MimeType" ); 00088 TQString service = desktopFile.readEntry( "X-KDE-ServiceType" ); 00089 00090 if ( mime.isEmpty() && service.isEmpty() ) 00091 { 00092 TQString tmp = TQString("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 || (mime == "media/builtin-mydocuments") 00103 || (mime == "media/builtin-mycomputer") 00104 || (mime == "media/builtin-mynetworkplaces") 00105 || (mime == "media/builtin-printers") 00106 || (mime == "media/builtin-trash") 00107 || (mime == "media/builtin-webbrowser") ) 00108 e = new KDEDesktopMimeType( &desktopFile ); 00109 else if ( mime == "application/x-executable" || mime == "application/x-pie-executable" || mime == "application/x-shellscript" ) 00110 e = new KExecMimeType( &desktopFile ); 00111 else if ( !mime.isEmpty() ) 00112 e = new KMimeType( &desktopFile ); 00113 else 00114 e = new KServiceType( &desktopFile ); 00115 00116 if (e->isDeleted()) 00117 { 00118 delete e; 00119 return 0; 00120 } 00121 00122 if ( !(e->isValid()) ) 00123 { 00124 kdWarning(7012) << "Invalid ServiceType : " << file << endl; 00125 delete e; 00126 return 0; 00127 } 00128 00129 return e; 00130 } 00131 00132 void 00133 KBuildServiceTypeFactory::saveHeader(TQDataStream &str) 00134 { 00135 KSycocaFactory::saveHeader(str); 00136 str << (TQ_INT32) m_fastPatternOffset; 00137 str << (TQ_INT32) m_otherPatternOffset; 00138 str << (TQ_INT32) m_propertyTypeDict.count(); 00139 00140 TQMapIterator<TQString, int> it; 00141 for (it = m_propertyTypeDict.begin(); it != m_propertyTypeDict.end(); ++it) 00142 { 00143 str << it.key() << (TQ_INT32)it.data(); 00144 } 00145 00146 } 00147 00148 void 00149 KBuildServiceTypeFactory::save(TQDataStream &str) 00150 { 00151 KSycocaFactory::save(str); 00152 00153 savePatternLists(str); 00154 00155 int endOfFactoryData = str.device()->at(); 00156 00157 // Update header (pass #3) 00158 saveHeader(str); 00159 00160 // Seek to end. 00161 str.device()->at(endOfFactoryData); 00162 } 00163 00164 void 00165 KBuildServiceTypeFactory::savePatternLists(TQDataStream &str) 00166 { 00167 // Store each patterns in one of the 2 string lists (for sorting) 00168 TQStringList fastPatterns; // for *.a to *.abcd 00169 TQStringList otherPatterns; // for the rest (core.*, *.tar.bz2, *~) ... 00170 TQDict<KMimeType> dict; 00171 00172 // For each mimetype in servicetypeFactory 00173 for(TQDictIterator<KSycocaEntry::Ptr> it ( *m_entryDict ); 00174 it.current(); 00175 ++it) 00176 { 00177 KSycocaEntry *entry = (*it.current()); 00178 if ( entry->isType( KST_KMimeType ) ) 00179 { 00180 KMimeType *mimeType = (KMimeType *) entry; 00181 TQStringList pat = mimeType->patterns(); 00182 TQStringList::ConstIterator patit = pat.begin(); 00183 for ( ; patit != pat.end() ; ++patit ) 00184 { 00185 const TQString &pattern = *patit; 00186 if ( pattern.findRev('*') == 0 00187 && pattern.findRev('.') == 1 00188 && pattern.length() <= 6 ) 00189 // it starts with "*.", has no other '*' and no other '.', and is max 6 chars 00190 // => fast patttern 00191 fastPatterns.append( pattern ); 00192 else if (!pattern.isEmpty()) // some stupid mimetype files have "Patterns=;" 00193 otherPatterns.append( pattern ); 00194 // Assumption : there is only one mimetype for that pattern 00195 // It doesn't really make sense otherwise, anyway. 00196 dict.replace( pattern, mimeType ); 00197 } 00198 } 00199 } 00200 // Sort the list - the fast one, useless for the other one 00201 fastPatterns.sort(); 00202 00203 TQ_INT32 entrySize = 0; 00204 TQ_INT32 nrOfEntries = 0; 00205 00206 m_fastPatternOffset = str.device()->at(); 00207 00208 // Write out fastPatternHeader (Pass #1) 00209 str.device()->at(m_fastPatternOffset); 00210 str << nrOfEntries; 00211 str << entrySize; 00212 00213 // For each fast pattern 00214 TQStringList::ConstIterator it = fastPatterns.begin(); 00215 for ( ; it != fastPatterns.end() ; ++it ) 00216 { 00217 int start = str.device()->at(); 00218 // Justify to 6 chars with spaces, so that the size remains constant 00219 // in the database file. 00220 TQString paddedPattern = (*it).leftJustify(6).right(4); // remove leading "*." 00221 //kdDebug(7021) << TQString("FAST : '%1' '%2'").arg(paddedPattern).arg(dict[(*it)]->name()) << endl; 00222 str << paddedPattern; 00223 str << dict[(*it)]->offset(); 00224 entrySize = str.device()->at() - start; 00225 nrOfEntries++; 00226 } 00227 00228 // store position 00229 m_otherPatternOffset = str.device()->at(); 00230 00231 // Write out fastPatternHeader (Pass #2) 00232 str.device()->at(m_fastPatternOffset); 00233 str << nrOfEntries; 00234 str << entrySize; 00235 00236 // For the other patterns 00237 str.device()->at(m_otherPatternOffset); 00238 00239 it = otherPatterns.begin(); 00240 for ( ; it != otherPatterns.end() ; ++it ) 00241 { 00242 //kdDebug(7021) << TQString("OTHER : '%1' '%2'").arg(*it).arg(dict[(*it)]->name()) << endl; 00243 str << (*it); 00244 str << dict[(*it)]->offset(); 00245 } 00246 00247 str << TQString(""); // end of list marker (has to be a string !) 00248 } 00249 00250 void 00251 KBuildServiceTypeFactory::addEntry(KSycocaEntry *newEntry, const char *resource) 00252 { 00253 KServiceType * serviceType = (KServiceType *) newEntry; 00254 if ( (*m_entryDict)[ newEntry->name() ] ) 00255 { 00256 // Already exists 00257 if (serviceType->desktopEntryPath().endsWith("kdelnk")) 00258 return; // Skip 00259 00260 // Replace 00261 KSycocaFactory::removeEntry(newEntry); 00262 } 00263 KSycocaFactory::addEntry(newEntry, resource); 00264 00265 00266 const TQMap<TQString,TQVariant::Type>& pd = serviceType->propertyDefs(); 00267 TQMap<TQString,TQVariant::Type>::ConstIterator pit = pd.begin(); 00268 for( ; pit != pd.end(); ++pit ) 00269 { 00270 if (!m_propertyTypeDict.contains(pit.key())) 00271 m_propertyTypeDict.insert(pit.key(), pit.data()); 00272 else if (m_propertyTypeDict[pit.key()] != pit.data()) 00273 kdWarning(7021) << "Property '"<< pit.key() << "' is defined multiple times ("<< serviceType->name() <<")" <<endl; 00274 } 00275 } 00276