kuserprofile.cpp
00001 /* This file is part of the KDE libraries 00002 * Copyright (C) 1999 Torben Weis <weis@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 "kuserprofile.h" 00020 #include "kservice.h" 00021 #include "kservicetype.h" 00022 #include "kservicetypefactory.h" 00023 00024 #include <kconfig.h> 00025 #include <kapplication.h> 00026 #include <kglobal.h> 00027 #include <kdebug.h> 00028 #include <kstaticdeleter.h> 00029 00030 #include <tqtl.h> 00031 00032 template class TQPtrList<KServiceTypeProfile>; 00033 typedef TQPtrList<KServiceTypeProfile> KServiceTypeProfileList; 00034 00035 /********************************************* 00036 * 00037 * KServiceTypeProfile 00038 * 00039 *********************************************/ 00040 00041 KServiceTypeProfileList* KServiceTypeProfile::s_lstProfiles = 0L; 00042 static KStaticDeleter< KServiceTypeProfileList > profileDeleter; 00043 bool KServiceTypeProfile::s_configurationMode = false; 00044 00045 void KServiceTypeProfile::initStatic() 00046 { 00047 if ( s_lstProfiles ) 00048 return; 00049 00050 // Make sure that a KServiceTypeFactory gets created. 00051 (void) KServiceTypeFactory::self(); 00052 00053 profileDeleter.setObject(s_lstProfiles, new KServiceTypeProfileList); 00054 s_lstProfiles->setAutoDelete( true ); 00055 00056 KConfig config( "profilerc", true, false); 00057 00058 static const TQString & defaultGroup = KGlobal::staticQString("<default>"); 00059 00060 TQStringList tmpList = config.groupList(); 00061 for (TQStringList::Iterator aIt = tmpList.begin(); 00062 aIt != tmpList.end(); ++aIt) { 00063 if ( *aIt == defaultGroup ) 00064 continue; 00065 00066 config.setGroup( *aIt ); 00067 00068 TQString appId = config.readEntry( "Application" ); 00069 00070 KService::Ptr pService = KService::serviceByStorageId(appId); 00071 00072 if ( pService ) { 00073 TQString application = pService->storageId(); 00074 TQString type = config.readEntry( "ServiceType" ); 00075 TQString type2 = config.readEntry( "GenericServiceType" ); 00076 if (type2.isEmpty()) // compat code 00077 type2 = (pService->type() == "Application") ? "Application" : "KParts/ReadOnlyPart"; 00078 int pref = config.readNumEntry( "Preference" ); 00079 00080 if ( !type.isEmpty() /* && pref >= 0*/ ) // Don't test for pref here. We want those in the list, to mark them as forbidden 00081 { 00082 KServiceTypeProfile* p = 00083 KServiceTypeProfile::serviceTypeProfile( type, type2 ); 00084 00085 if ( !p ) { 00086 p = new KServiceTypeProfile( type, type2 ); 00087 s_lstProfiles->append( p ); 00088 } 00089 00090 bool allow = config.readBoolEntry( "AllowAsDefault" ); 00091 //kdDebug(7014) << "KServiceTypeProfile::initStatic adding service " << application << " to profile for " << type << "," << type2 << " with preference " << pref << endl; 00092 p->addService( application, pref, allow ); 00093 } 00094 } 00095 } 00096 } 00097 00098 //static 00099 void KServiceTypeProfile::clear() 00100 { 00101 // HACK ksycoca may open the dummy db, in such case the first call to ksycoca 00102 // in initStatic() leads to closing the dummy db and clear() being called 00103 // in the middle of it, making s_lstProfiles be NULL 00104 if( s_lstProfiles == NULL || s_lstProfiles->count() == 0 ) 00105 return; 00106 profileDeleter.destructObject(); 00107 } 00108 00109 //static 00110 KServiceTypeProfile::OfferList KServiceTypeProfile::offers( const TQString& _servicetype, const TQString& _genericServiceType ) 00111 { 00112 OfferList offers; 00113 TQStringList serviceList; 00114 //kdDebug(7014) << "KServiceTypeProfile::offers( " << _servicetype << "," << _genericServiceType << " )" << endl; 00115 00116 // Note that KServiceTypeProfile::offers() calls KServiceType::offers(), 00117 // so we _do_ get the new services, that are available but not in the profile. 00118 if ( _genericServiceType.isEmpty() ) 00119 { 00120 initStatic(); 00121 // We want all profiles for servicetype, if we have profiles. 00122 // ## Slow loop, if profilerc is big. We should use a map instead? 00123 TQPtrListIterator<KServiceTypeProfile> it( *s_lstProfiles ); 00124 for( ; it.current(); ++it ) 00125 if ( it.current()->m_strServiceType == _servicetype ) 00126 { 00127 offers += it.current()->offers(); 00128 } 00129 //kdDebug(7014) << "Found profile: " << offers.count() << " offers" << endl; 00130 } 00131 else 00132 { 00133 KServiceTypeProfile* profile = serviceTypeProfile( _servicetype, _genericServiceType ); 00134 if ( profile ) 00135 { 00136 //kdDebug(7014) << "Found profile: " << profile->offers().count() << " offers" << endl; 00137 offers += profile->offers(); 00138 } 00139 else 00140 { 00141 // Try the other way round, order is not like size, it doesn't matter. 00142 profile = serviceTypeProfile( _genericServiceType, _servicetype ); 00143 if ( profile ) 00144 { 00145 //kdDebug(7014) << "Found profile after switching: " << profile->offers().count() << " offers" << endl; 00146 offers += profile->offers(); 00147 } 00148 } 00149 } 00150 00151 // Collect services, to make the next loop faster 00152 OfferList::Iterator itOffers = offers.begin(); 00153 for( ; itOffers != offers.end(); ++itOffers ) 00154 serviceList += (*itOffers).service()->desktopEntryPath(); // this should identify each service uniquely 00155 //kdDebug(7014) << "serviceList: " << serviceList.join(",") << endl; 00156 00157 // Now complete with any other offers that aren't in the profile 00158 // This can be because the services have been installed after the profile was written, 00159 // but it's also the case for any service that's neither App nor ReadOnlyPart, e.g. RenameDlg/Plugin 00160 KService::List list = KServiceType::offers( _servicetype ); 00161 //kdDebug(7014) << "Using KServiceType::offers, result: " << list.count() << " offers" << endl; 00162 TQValueListIterator<KService::Ptr> it = list.begin(); 00163 for( ; it != list.end(); ++it ) 00164 { 00165 if (_genericServiceType.isEmpty() /*no constraint*/ || (*it)->hasServiceType( _genericServiceType )) 00166 { 00167 // Check that we don't already have it ;) 00168 if ( serviceList.find( (*it)->desktopEntryPath() ) == serviceList.end() ) 00169 { 00170 bool allow = (*it)->allowAsDefault(); 00171 KServiceOffer o( (*it), (*it)->initialPreferenceForMimeType(_servicetype), allow ); 00172 offers.append( o ); 00173 //kdDebug(7014) << "Appending offer " << (*it)->name() << " initial preference=" << (*it)->initialPreference() << " allow-as-default=" << allow << endl; 00174 } 00175 //else 00176 // kdDebug(7014) << "Already having offer " << (*it)->name() << endl; 00177 } 00178 } 00179 00180 qBubbleSort( offers ); 00181 00182 #if 0 00183 // debug code, comment if you wish but don't remove. 00184 kdDebug(7014) << "Sorted list:" << endl; 00185 OfferList::Iterator itOff = offers.begin(); 00186 for( ; itOff != offers.end(); ++itOff ) 00187 kdDebug(7014) << (*itOff).service()->name() << " allow-as-default=" << (*itOff).allowAsDefault() << endl; 00188 #endif 00189 00190 //kdDebug(7014) << "Returning " << offers.count() << " offers" << endl; 00191 return offers; 00192 } 00193 00194 KServiceTypeProfile::KServiceTypeProfile( const TQString& _servicetype, const TQString& _genericServiceType ) 00195 { 00196 initStatic(); 00197 00198 m_strServiceType = _servicetype; 00199 m_strGenericServiceType = _genericServiceType; 00200 } 00201 00202 KServiceTypeProfile::~KServiceTypeProfile() 00203 { 00204 } 00205 00206 void KServiceTypeProfile::addService( const TQString& _service, 00207 int _preference, bool _allow_as_default ) 00208 { 00209 m_mapServices[ _service ].m_iPreference = _preference; 00210 m_mapServices[ _service ].m_bAllowAsDefault = _allow_as_default; 00211 } 00212 00213 int KServiceTypeProfile::preference( const TQString& _service ) const 00214 { 00215 KService::Ptr service = KService::serviceByName( _service ); 00216 if (!service) 00217 return 0; 00218 TQMap<TQString,Service>::ConstIterator it = m_mapServices.find( service->storageId() ); 00219 if ( it == m_mapServices.end() ) 00220 return 0; 00221 00222 return it.data().m_iPreference; 00223 } 00224 00225 bool KServiceTypeProfile::allowAsDefault( const TQString& _service ) const 00226 { 00227 KService::Ptr service = KService::serviceByName( _service ); 00228 if (!service) 00229 return false; 00230 00231 // Does the service itself not allow that ? 00232 if ( !service->allowAsDefault() ) 00233 return false; 00234 00235 // Look what the user says ... 00236 TQMap<TQString,Service>::ConstIterator it = m_mapServices.find( service->storageId() ); 00237 if ( it == m_mapServices.end() ) 00238 return 0; 00239 00240 return it.data().m_bAllowAsDefault; 00241 } 00242 00243 KServiceTypeProfile* KServiceTypeProfile::serviceTypeProfile( const TQString& _servicetype, const TQString& _genericServiceType ) 00244 { 00245 initStatic(); 00246 static const TQString& app_str = KGlobal::staticQString("Application"); 00247 00248 const TQString &_genservicetype = ((!_genericServiceType.isEmpty()) ? _genericServiceType : app_str); 00249 00250 TQPtrListIterator<KServiceTypeProfile> it( *s_lstProfiles ); 00251 for( ; it.current(); ++it ) 00252 if (( it.current()->m_strServiceType == _servicetype ) && 00253 ( it.current()->m_strGenericServiceType == _genservicetype)) 00254 return it.current(); 00255 00256 return 0; 00257 } 00258 00259 00260 KServiceTypeProfile::OfferList KServiceTypeProfile::offers() const 00261 { 00262 OfferList offers; 00263 00264 kdDebug(7014) << "KServiceTypeProfile::offers serviceType=" << m_strServiceType << " genericServiceType=" << m_strGenericServiceType << endl; 00265 KService::List list = KServiceType::offers( m_strServiceType ); 00266 TQValueListIterator<KService::Ptr> it = list.begin(); 00267 for( ; it != list.end(); ++it ) 00268 { 00269 //kdDebug(7014) << "KServiceTypeProfile::offers considering " << (*it)->name() << endl; 00270 if ( m_strGenericServiceType.isEmpty() || (*it)->hasServiceType( m_strGenericServiceType ) ) 00271 { 00272 // Now look into the profile, to find this service's preference. 00273 TQMap<TQString,Service>::ConstIterator it2 = m_mapServices.find( (*it)->storageId() ); 00274 00275 if( it2 != m_mapServices.end() ) 00276 { 00277 //kdDebug(7014) << "found in mapServices pref=" << it2.data().m_iPreference << endl; 00278 if ( it2.data().m_iPreference > 0 ) { 00279 bool allow = (*it)->allowAsDefault(); 00280 if ( allow ) 00281 allow = it2.data().m_bAllowAsDefault; 00282 KServiceOffer o( (*it), it2.data().m_iPreference, allow ); 00283 offers.append( o ); 00284 } 00285 } 00286 else 00287 { 00288 //kdDebug(7014) << "not found in mapServices. Appending." << endl; 00289 // We use 0 as the preference to ensure new apps don't take over existing apps (which default to 1) 00290 KServiceOffer o( (*it), 0, (*it)->allowAsDefault() ); 00291 offers.append( o ); 00292 } 00293 }/* else 00294 kdDebug(7014) << "Doesn't have " << m_strGenericServiceType << endl;*/ 00295 } 00296 00297 qBubbleSort( offers ); 00298 00299 //kdDebug(7014) << "KServiceTypeProfile::offers returning " << offers.count() << " offers" << endl; 00300 return offers; 00301 } 00302 00303 KService::Ptr KServiceTypeProfile::preferredService( const TQString & _serviceType, const TQString & _genericServiceType ) 00304 { 00305 OfferList lst = offers( _serviceType, _genericServiceType ); 00306 00307 OfferList::Iterator itOff = lst.begin(); 00308 // Look for the first one that is allowed as default. 00309 // Since the allowed-as-default are first anyway, we only have 00310 // to look at the first one to know. 00311 if( itOff != lst.end() && (*itOff).allowAsDefault() ) 00312 return (*itOff).service(); 00313 00314 //kdDebug(7014) << "No offers, or none allowed as default" << endl; 00315 return 0L; 00316 } 00317 00318 /********************************************* 00319 * 00320 * KServiceOffer 00321 * 00322 *********************************************/ 00323 00324 KServiceOffer::KServiceOffer() 00325 { 00326 m_iPreference = -1; 00327 } 00328 00329 KServiceOffer::KServiceOffer( const KServiceOffer& _o ) 00330 { 00331 m_pService = _o.m_pService; 00332 m_iPreference = _o.m_iPreference; 00333 m_bAllowAsDefault = _o.m_bAllowAsDefault; 00334 } 00335 00336 KServiceOffer::KServiceOffer( KService::Ptr _service, int _pref, bool _default ) 00337 { 00338 m_pService = _service; 00339 m_iPreference = _pref; 00340 m_bAllowAsDefault = _default; 00341 } 00342 00343 00344 bool KServiceOffer::operator< ( const KServiceOffer& _o ) const 00345 { 00346 // Put offers allowed as default FIRST. 00347 if ( _o.m_bAllowAsDefault && !m_bAllowAsDefault ) 00348 return false; // _o is default and not 'this'. 00349 if ( !_o.m_bAllowAsDefault && m_bAllowAsDefault ) 00350 return true; // 'this' is default but not _o. 00351 // Both offers are allowed or not allowed as default 00352 // -> use preferences to sort them 00353 // The bigger the better, but we want the better FIRST 00354 return _o.m_iPreference < m_iPreference; 00355 }