kurifilter.cpp
00001 /* This file is part of the KDE libraries 00002 * Copyright (C) 2000 Yves Arrouye <yves@realnames.com> 00003 * Copyright (C) 2000 Dawit Alemayehu <adawit at kde.org> 00004 * 00005 * This library is free software; you can redistribute it and/or 00006 * modify it under the terms of the GNU Library General Public 00007 * License as published by the Free Software Foundation; either 00008 * version 2 of the License, or (at your option) any later version. 00009 * 00010 * This library is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 * Library General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU Library General Public License 00016 * along with this library; see the file COPYING.LIB. If not, write to 00017 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00018 * Boston, MA 02110-1301, USA. 00019 **/ 00020 00021 #include <config.h> 00022 00023 #include <kdebug.h> 00024 #include <kiconloader.h> 00025 #include <ktrader.h> 00026 #include <kmimetype.h> 00027 #include <klibloader.h> 00028 #include <kstaticdeleter.h> 00029 #include <tdeparts/componentfactory.h> 00030 00031 #ifdef HAVE_ELFICON 00032 #include <tqimage.h> 00033 #include "tdelficon.h" 00034 #endif // HAVE_ELFICON 00035 00036 #include "kurifilter.h" 00037 00038 template class TQPtrList<KURIFilterPlugin>; 00039 00040 KURIFilterPlugin::KURIFilterPlugin( TQObject *parent, const char *name, double pri ) 00041 :TQObject( parent, name ) 00042 { 00043 m_strName = TQString::fromLatin1( name ); 00044 m_dblPriority = pri; 00045 } 00046 00047 void KURIFilterPlugin::setFilteredURI( KURIFilterData& data, const KURL& uri ) const 00048 { 00049 if ( data.uri() != uri ) 00050 { 00051 data.m_pURI = uri; 00052 data.m_bChanged = true; 00053 } 00054 } 00055 00056 class KURIFilterDataPrivate 00057 { 00058 public: 00059 KURIFilterDataPrivate() {}; 00060 TQString abs_path; 00061 TQString args; 00062 TQString typedString; 00063 }; 00064 00065 KURIFilterData::KURIFilterData( const KURIFilterData& data ) 00066 { 00067 m_iType = data.m_iType; 00068 m_pURI = data.m_pURI; 00069 m_strErrMsg = data.m_strErrMsg; 00070 m_strIconName = data.m_strIconName; 00071 m_bChanged = data.m_bChanged; 00072 m_bCheckForExecutables = data.m_bCheckForExecutables; 00073 d = new KURIFilterDataPrivate; 00074 d->abs_path = data.absolutePath(); 00075 d->typedString = data.typedString(); 00076 d->args = data.argsAndOptions(); 00077 } 00078 00079 KURIFilterData::~KURIFilterData() 00080 { 00081 delete d; 00082 d = 0; 00083 } 00084 00085 void KURIFilterData::init( const KURL& url ) 00086 { 00087 m_iType = KURIFilterData::UNKNOWN; 00088 m_pURI = url; 00089 m_strErrMsg = TQString::null; 00090 m_strIconName = TQString::null; 00091 m_bCheckForExecutables = true; 00092 m_bChanged = true; 00093 d = new KURIFilterDataPrivate; 00094 d->typedString = url.url(); 00095 } 00096 00097 void KURIFilterData::init( const TQString& url ) 00098 { 00099 m_iType = KURIFilterData::UNKNOWN; 00100 m_pURI = url; 00101 m_strErrMsg = TQString::null; 00102 m_strIconName = TQString::null; 00103 m_bCheckForExecutables = true; 00104 m_bChanged = true; 00105 d = new KURIFilterDataPrivate; 00106 d->typedString = url; 00107 } 00108 00109 void KURIFilterData::reinit(const KURL &url) 00110 { 00111 delete d; 00112 init(url); 00113 } 00114 00115 void KURIFilterData::reinit(const TQString &url) 00116 { 00117 delete d; 00118 init(url); 00119 } 00120 00121 TQString KURIFilterData::typedString() const 00122 { 00123 return d->typedString; 00124 } 00125 00126 void KURIFilterData::setCheckForExecutables( bool check ) 00127 { 00128 m_bCheckForExecutables = check; 00129 } 00130 00131 bool KURIFilterData::hasArgsAndOptions() const 00132 { 00133 return !d->args.isEmpty(); 00134 } 00135 00136 bool KURIFilterData::hasAbsolutePath() const 00137 { 00138 return !d->abs_path.isEmpty(); 00139 } 00140 00141 bool KURIFilterData::setAbsolutePath( const TQString& absPath ) 00142 { 00143 // Since a malformed URL could possibly be a relative 00144 // URL we tag it as a possible local resource... 00145 if( (!m_pURI.isValid() || m_pURI.isLocalFile()) ) 00146 { 00147 d->abs_path = absPath; 00148 return true; 00149 } 00150 return false; 00151 } 00152 00153 TQString KURIFilterData::absolutePath() const 00154 { 00155 return d->abs_path; 00156 } 00157 00158 TQString KURIFilterData::argsAndOptions() const 00159 { 00160 return d->args; 00161 } 00162 00163 TQString KURIFilterData::iconName() 00164 { 00165 if( m_bChanged ) 00166 { 00167 m_customIconPixmap = TQPixmap(); 00168 switch ( m_iType ) 00169 { 00170 case KURIFilterData::LOCAL_FILE: 00171 case KURIFilterData::LOCAL_DIR: 00172 case KURIFilterData::NET_PROTOCOL: 00173 { 00174 m_strIconName = KMimeType::iconForURL( m_pURI ); 00175 break; 00176 } 00177 case KURIFilterData::EXECUTABLE: 00178 { 00179 TQString exeName = m_pURI.url(); 00180 exeName = exeName.mid( exeName.findRev( '/' ) + 1 ); // strip path if given 00181 KService::Ptr service = KService::serviceByDesktopName( exeName ); 00182 #ifndef HAVE_ELFICON 00183 // Try to find an icon with the same name as the binary (useful for non-tde apps) 00184 // FIXME: We should only do this if the binary is in the system path somewhere, 00185 // otherwise TDE could end up showing system icons for user binaries 00186 if (service && service->icon() != TQString::fromLatin1( "unknown" )) { 00187 m_strIconName = service->icon(); 00188 } 00189 else if ( !TDEGlobal::iconLoader()->loadIcon( exeName, TDEIcon::NoGroup, 16, TDEIcon::DefaultState, 0, true ).isNull() ) { 00190 m_strIconName = exeName; 00191 } 00192 else { 00193 // use default 00194 m_strIconName = TQString::fromLatin1("application-x-executable"); 00195 } 00196 #else // HAVE_ELFICON 00197 // Try to find an icon with the same name as the binary (useful for non-tde apps) 00198 // FIXME: We should only do this if the binary is in the system path somewhere, 00199 // otherwise TDE could end up showing system icons for user binaries 00200 if (service && service->icon() != TQString::fromLatin1( "unknown" )) { 00201 m_strIconName = service->icon(); 00202 } 00203 else if ( !TDEGlobal::iconLoader()->loadIcon( exeName, TDEIcon::NoGroup, 16, TDEIcon::DefaultState, 0, true ).isNull() ) { 00204 m_strIconName = exeName; 00205 } 00206 else { 00207 // use default 00208 m_strIconName = TQString::fromLatin1("application-x-executable"); 00209 } 00210 // Try to load from elf file (if supported) 00211 // Check for an embedded icon 00212 unsigned int icon_size; 00213 libr_icon *icon = NULL; 00214 libr_file *handle = NULL; 00215 libr_access_t access = LIBR_READ; 00216 char libr_can_continue = 1; 00217 00218 if((handle = libr_open(const_cast<char*>(m_pURI.path().ascii()), access)) == NULL) 00219 { 00220 kdWarning() << "failed to open file " << m_pURI.path() << endl; 00221 libr_can_continue = 0; 00222 } 00223 00224 if (libr_can_continue == 1) { 00225 icon_size = 32; // FIXME: Is this a reasonable size request for all possible usages of kurifilter? 00226 icon = libr_icon_geticon_bysize(handle, icon_size); 00227 00228 if (libr_can_continue == 1) { 00229 // See if the embedded icon name matches any icon file names already on the system 00230 // If it does, use the system icon instead of the embedded one 00231 int iconresnamefound = 0; 00232 iconentry *entry = NULL; 00233 iconlist icons; 00234 if(!get_iconlist(handle, &icons)) 00235 { 00236 // Failed to obtain a list of ELF icons 00237 kdDebug() << "failed to obtain ELF icon from " << m_pURI.path() << ": " << libr_errmsg() << endl; 00238 00239 // See if there is a system icon we can use 00240 TQString sysIconName = elf_get_resource(handle, ".metadata_sysicon"); 00241 if (!sysIconName.isEmpty()) { 00242 if (TDEGlobal::iconLoader()->iconPath(sysIconName.ascii(), 0, true) != "") { 00243 m_strIconName = sysIconName; 00244 } 00245 } 00246 00247 libr_close(handle); 00248 libr_can_continue = 0; 00249 } 00250 else { 00251 while((entry = get_nexticon(&icons, entry)) != NULL) 00252 { 00253 if(icon == NULL) 00254 { 00255 // Try loading this icon as fallback 00256 icon = libr_icon_geticon_byname(handle, entry->name); 00257 } 00258 if (TDEGlobal::iconLoader()->iconPath(entry->name, 0, true) != "") { 00259 iconresnamefound = 1; 00260 m_strIconName = entry->name; 00261 break; 00262 } 00263 } 00264 } 00265 00266 if (libr_can_continue == 1) { 00267 if ((iconresnamefound == 0) && (icon)) { 00268 // Extract the embedded icon 00269 size_t icon_data_length; 00270 char* icondata = libr_icon_malloc(icon, &icon_data_length); 00271 m_customIconPixmap.loadFromData(static_cast<uchar*>(static_cast<void*>(icondata)), icon_data_length); // EVIL CAST 00272 if (icon_size != 0) { 00273 TQImage ip = m_customIconPixmap.convertToImage(); 00274 ip = ip.smoothScale(icon_size, icon_size); 00275 m_customIconPixmap.convertFromImage(ip); 00276 } 00277 free(icondata); 00278 libr_icon_close(icon); 00279 } 00280 00281 libr_close(handle); 00282 } 00283 } 00284 } 00285 #endif // HAVE_ELFICON 00286 break; 00287 } 00288 case KURIFilterData::HELP: 00289 { 00290 m_strIconName = TQString::fromLatin1("khelpcenter"); 00291 break; 00292 } 00293 case KURIFilterData::SHELL: 00294 { 00295 m_strIconName = TQString::fromLatin1("konsole"); 00296 break; 00297 } 00298 case KURIFilterData::ERROR: 00299 case KURIFilterData::BLOCKED: 00300 { 00301 m_strIconName = TQString::fromLatin1("error"); 00302 break; 00303 } 00304 default: 00305 m_strIconName = TQString::null; 00306 break; 00307 } 00308 m_bChanged = false; 00309 } 00310 return m_strIconName; 00311 } 00312 00313 TQPixmap KURIFilterData::customIconPixmap() 00314 { 00315 return m_customIconPixmap; 00316 } 00317 00318 //******************************************** KURIFilterPlugin ********************************************** 00319 void KURIFilterPlugin::setArguments( KURIFilterData& data, const TQString& args ) const 00320 { 00321 data.d->args = args; 00322 } 00323 00324 //******************************************** KURIFilter ********************************************** 00325 KURIFilter *KURIFilter::s_self; 00326 static KStaticDeleter<KURIFilter> kurifiltersd; 00327 00328 KURIFilter *KURIFilter::self() 00329 { 00330 if (!s_self) 00331 s_self = kurifiltersd.setObject(s_self, new KURIFilter); 00332 return s_self; 00333 } 00334 00335 KURIFilter::KURIFilter() 00336 { 00337 m_lstPlugins.setAutoDelete(true); 00338 loadPlugins(); 00339 } 00340 00341 KURIFilter::~KURIFilter() 00342 { 00343 } 00344 00345 bool KURIFilter::filterURI( KURIFilterData& data, const TQStringList& filters ) 00346 { 00347 bool filtered = false; 00348 KURIFilterPluginList use_plugins; 00349 00350 // If we have a filter list, only include the once 00351 // explicitly specified by it. Otherwise, use all available filters... 00352 if( filters.isEmpty() ) 00353 use_plugins = m_lstPlugins; // Use everything that is loaded... 00354 else 00355 { 00356 //kdDebug() << "Named plugins requested..." << endl; 00357 for( TQStringList::ConstIterator lst = filters.begin(); lst != filters.end(); ++lst ) 00358 { 00359 TQPtrListIterator<KURIFilterPlugin> it( m_lstPlugins ); 00360 for( ; it.current() ; ++it ) 00361 { 00362 if( (*lst) == it.current()->name() ) 00363 { 00364 //kdDebug() << "Will use filter plugin named: " << it.current()->name() << endl; 00365 use_plugins.append( it.current() ); 00366 break; // We already found it ; so lets test the next named filter... 00367 } 00368 } 00369 } 00370 } 00371 00372 TQPtrListIterator<KURIFilterPlugin> it( use_plugins ); 00373 //kdDebug() << "Using " << use_plugins.count() << " out of the " 00374 // << m_lstPlugins.count() << " available plugins" << endl; 00375 for (; it.current() && !filtered; ++it) 00376 { 00377 //kdDebug() << "Using a filter plugin named: " << it.current()->name() << endl; 00378 filtered |= it.current()->filterURI( data ); 00379 } 00380 return filtered; 00381 } 00382 00383 bool KURIFilter::filterURI( KURL& uri, const TQStringList& filters ) 00384 { 00385 KURIFilterData data = uri; 00386 bool filtered = filterURI( data, filters ); 00387 if( filtered ) uri = data.uri(); 00388 return filtered; 00389 } 00390 00391 bool KURIFilter::filterURI( TQString& uri, const TQStringList& filters ) 00392 { 00393 KURIFilterData data = uri; 00394 bool filtered = filterURI( data, filters ); 00395 if( filtered ) uri = data.uri().url(); 00396 return filtered; 00397 00398 } 00399 00400 KURL KURIFilter::filteredURI( const KURL &uri, const TQStringList& filters ) 00401 { 00402 KURIFilterData data = uri; 00403 filterURI( data, filters ); 00404 return data.uri(); 00405 } 00406 00407 TQString KURIFilter::filteredURI( const TQString &uri, const TQStringList& filters ) 00408 { 00409 KURIFilterData data = uri; 00410 filterURI( data, filters ); 00411 return data.uri().url(); 00412 } 00413 00414 TQPtrListIterator<KURIFilterPlugin> KURIFilter::pluginsIterator() const 00415 { 00416 return TQPtrListIterator<KURIFilterPlugin>(m_lstPlugins); 00417 } 00418 00419 TQStringList KURIFilter::pluginNames() const 00420 { 00421 TQStringList list; 00422 for(TQPtrListIterator<KURIFilterPlugin> i = pluginsIterator(); *i; ++i) 00423 list.append((*i)->name()); 00424 return list; 00425 } 00426 00427 void KURIFilter::loadPlugins() 00428 { 00429 TDETrader::OfferList offers = TDETrader::self()->query( "KURIFilter/Plugin" ); 00430 00431 TDETrader::OfferList::ConstIterator it = offers.begin(); 00432 TDETrader::OfferList::ConstIterator end = offers.end(); 00433 00434 for (; it != end; ++it ) 00435 { 00436 KURIFilterPlugin *plugin = KParts::ComponentFactory::createInstanceFromService<KURIFilterPlugin>( *it, 0, (*it)->desktopEntryName().latin1() ); 00437 if ( plugin ) 00438 m_lstPlugins.append( plugin ); 00439 } 00440 00441 // NOTE: Plugin priority is now determined by 00442 // the entry in the .desktop files... 00443 // TODO: Config dialog to differentiate "system" 00444 // plugins from "user-defined" ones... 00445 // m_lstPlugins.sort(); 00446 } 00447 00448 void KURIFilterPlugin::virtual_hook( int, void* ) 00449 { /*BASE::virtual_hook( id, data );*/ } 00450 00451 #include "kurifilter.moc"