1/* 2 * This file Copyright (C) Mnemosyne LLC 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 6 * as published by the Free Software Foundation. 7 * 8 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 9 * 10 * $Id: favicon.cc 11522 2010-12-12 16:43:19Z charles $ 11 */ 12 13#include <QDesktopServices> 14#include <QDir> 15#include <QNetworkAccessManager> 16#include <QNetworkReply> 17#include <QNetworkRequest> 18 19#include "favicon.h" 20 21/*** 22**** 23***/ 24 25Favicons :: Favicons( ) 26{ 27 myNAM = new QNetworkAccessManager( ); 28 connect( myNAM, SIGNAL(finished(QNetworkReply*)), this, SLOT(onRequestFinished(QNetworkReply*)) ); 29} 30 31Favicons :: ~Favicons( ) 32{ 33 delete myNAM; 34} 35 36/*** 37**** 38***/ 39 40QString 41Favicons :: getCacheDir( ) 42{ 43 const QString base = QDesktopServices::storageLocation( QDesktopServices::CacheLocation ); 44 return QDir( base ).absoluteFilePath( "favicons" ); 45} 46 47void 48Favicons :: ensureCacheDirHasBeenScanned( ) 49{ 50 static bool hasBeenScanned = false; 51 52 if( !hasBeenScanned ) 53 { 54 hasBeenScanned = true; 55 56 QDir cacheDir( getCacheDir( ) ); 57 cacheDir.mkpath( cacheDir.absolutePath( ) ); 58 59 QStringList files = cacheDir.entryList( QDir::Files|QDir::Readable ); 60 foreach( QString file, files ) { 61 QPixmap pixmap; 62 pixmap.load( cacheDir.absoluteFilePath( file ) ); 63 if( !pixmap.isNull( ) ) 64 myPixmaps.insert( file, pixmap ); 65 } 66 } 67} 68 69QString 70Favicons :: getHost( const QUrl& url ) 71{ 72 QString host = url.host( ); 73 const int first_dot = host.indexOf( '.' ); 74 const int last_dot = host.lastIndexOf( '.' ); 75 76 if( ( first_dot != -1 ) && ( last_dot != -1 ) && ( first_dot != last_dot ) ) 77 host.remove( 0, first_dot + 1 ); 78 79 return host; 80} 81 82QPixmap 83Favicons :: find( const QUrl& url ) 84{ 85 return findFromHost( getHost( url ) ); 86} 87 88namespace 89{ 90 const QSize rightSize( 16, 16 ); 91}; 92 93QPixmap 94Favicons :: findFromHost( const QString& host ) 95{ 96 ensureCacheDirHasBeenScanned( ); 97 98 const QPixmap pixmap = myPixmaps[ host ]; 99 return pixmap.size()==rightSize ? pixmap : pixmap.scaled(rightSize); 100} 101 102void 103Favicons :: add( const QUrl& url ) 104{ 105 ensureCacheDirHasBeenScanned( ); 106 107 const QString host = getHost( url ); 108 109 if( !myPixmaps.contains( host ) ) 110 { 111 // add a placholder s.t. we only ping the server once per session 112 QPixmap tmp( rightSize ); 113 tmp.fill( Qt::transparent ); 114 myPixmaps.insert( host, tmp ); 115 116 // try to download the favicon 117 const QString path = "http://" + host + "/favicon."; 118 QStringList suffixes; 119 suffixes << "ico" << "png" << "gif" << "jpg"; 120 foreach( QString suffix, suffixes ) 121 myNAM->get( QNetworkRequest( path + suffix ) ); 122 } 123} 124 125void 126Favicons :: onRequestFinished( QNetworkReply * reply ) 127{ 128 const QString host = reply->url().host(); 129 130 QPixmap pixmap; 131 132 const QByteArray content = reply->readAll( ); 133 if( !reply->error( ) ) 134 pixmap.loadFromData( content ); 135 136 if( !pixmap.isNull( ) ) 137 { 138 // save it in memory... 139 myPixmaps.insert( host, pixmap ); 140 141 // save it on disk... 142 QDir cacheDir( getCacheDir( ) ); 143 cacheDir.mkpath( cacheDir.absolutePath( ) ); 144 QFile file( cacheDir.absoluteFilePath( host ) ); 145 file.open( QIODevice::WriteOnly ); 146 file.write( content ); 147 file.close( ); 148 149 // notify listeners 150 emit pixmapReady( host ); 151 } 152} 153