(trunk qt) add code for a favicon cache -- it even shares the GTK+ client's favicon cache directory. :) This isn't plugged in anywhere yet, but will be useful when the filterbar and trackers tab are synced with the GTK+ client.

This commit is contained in:
Charles Kerr 2010-07-25 17:16:03 +00:00
parent 12feea7c42
commit 8034e06cf2
5 changed files with 221 additions and 8 deletions

View File

@ -15,6 +15,7 @@
#include <QApplication>
#include <QTimer>
#include "favicon.h"
class Prefs;
class Session;
@ -33,6 +34,9 @@ class MyApp: public QApplication
public:
void raise( );
public:
Favicons favicons;
private:
Prefs * myPrefs;
Session * mySession;

142
qt/favicon.cc Normal file
View File

@ -0,0 +1,142 @@
/*
* This file Copyright (C) 2010 Mnemosyne LLC
*
* This file is licensed by the GPL version 2. Works owned by the
* Transmission project are granted a special exemption to clause 2(b)
* so that the bulk of its code can remain under the MIT license.
* This exemption does not extend to derived works not owned by
* the Transmission project.
*
* $Id$
*/
#include <iostream>
#include <QDesktopServices>
#include <QDir>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include "favicon.h"
/***
****
***/
QString
Favicons :: getCacheDir( )
{
const QString base = QDesktopServices::storageLocation( QDesktopServices::CacheLocation );
return QDir( base ).absoluteFilePath( "favicons" );
};
Favicons :: Favicons( )
{
myNAM = new QNetworkAccessManager( );
connect( myNAM, SIGNAL(finished(QNetworkReply*)), this, SLOT(onRequestFinished(QNetworkReply*)) );
}
Favicons :: ~Favicons( )
{
delete myNAM;
}
/***
****
***/
void
Favicons :: ensureCacheDirHasBeenScanned( )
{
static bool hasBeenScanned = false;
if( !hasBeenScanned )
{
hasBeenScanned = true;
QDir cacheDir( getCacheDir( ) );
cacheDir.mkpath( cacheDir.absolutePath( ) );
QStringList files = cacheDir.entryList( QDir::Files|QDir::Readable );
foreach( QString file, files ) {
QPixmap pixmap;
pixmap.load( cacheDir.absoluteFilePath( file ) );
if( !pixmap.isNull( ) )
myPixmaps.insert( file, pixmap );
}
}
}
QString
Favicons :: getHost( const QUrl& url )
{
QString host = url.host( );
const int first_dot = host.indexOf( '.' );
const int last_dot = host.lastIndexOf( '.' );
if( ( first_dot != -1 ) && ( last_dot != -1 ) && ( first_dot != last_dot ) )
host.remove( 0, first_dot + 1 );
return host;
}
QPixmap
Favicons :: find( const QUrl& url )
{
ensureCacheDirHasBeenScanned( );
return myPixmaps[ getHost(url) ];
}
void
Favicons :: add( const QUrl& url_in )
{
ensureCacheDirHasBeenScanned( );
const QString host = getHost(url_in);
if( !myPixmaps.contains(host) && !myPending.contains(host) )
{
const int IMAGE_TYPES = 4;
const QString image_types[IMAGE_TYPES] = { "ico", "png", "gif", "jpg" };
myPending.append( host );
for( int i=0; i<IMAGE_TYPES; ++i )
{
QString url( "http://" + host + "/favicon." + image_types[i]);
myNAM->get( QNetworkRequest( url ) );
}
}
}
void
Favicons :: onRequestFinished( QNetworkReply * reply )
{
const QString host = reply->url().host();
myPending.removeAll( host );
const QByteArray content = reply->readAll( );
QPixmap pixmap;
if( !reply->error( ) )
pixmap.loadFromData( content );
if( !pixmap.isNull( ) )
{
// save it in memory...
myPixmaps.insert( host, pixmap );
// save it on disk...
QDir cacheDir( getCacheDir( ) );
cacheDir.mkpath( cacheDir.absolutePath( ) );
QFile file( cacheDir.absoluteFilePath( host ) );
file.open( QIODevice::WriteOnly );
file.write( content );
file.close( );
// notify listeners
emit pixmapReady( host );
}
}

62
qt/favicon.h Normal file
View File

@ -0,0 +1,62 @@
/*
* This file Copyright (C) 2010 Mnemosyne LLC
*
* This file is licensed by the GPL version 2. Works owned by the
* Transmission project are granted a special exemption to clause 2(b)
* so that the bulk of its code can remain under the MIT license.
* This exemption does not extend to derived works not owned by
* the Transmission project.
*
* $Id$
*/
#ifndef FAVICON_CACHE_H
#define FAVICON_CACHE_H
class QNetworkAccessManager;
class QNetworkReply;
class QUrl;
#include <QMap>
#include <QString>
#include <QStringList>
#include <QObject>
#include <QPixmap>
class Favicons: public QObject
{
Q_OBJECT;
public:
Favicons();
virtual ~Favicons();
/* returns a cached pixmap, or a NULL pixmap if there's no match in the cache */
QPixmap find( const QUrl& url );
/* this will emit a signal when (if) the icon becomes ready */
void add( const QUrl& url );
signals:
void pixmapReady( const QString& host );
private:
QStringList myPending;
QNetworkAccessManager * myNAM;
QMap<QString,QPixmap> myPixmaps;
QString getHost( const QUrl& url );
QString getCacheDir( );
void ensureCacheDirHasBeenScanned( );
private slots:
void onRequestFinished( QNetworkReply * reply );
};
#endif

View File

@ -30,12 +30,13 @@ TRANSLATIONS += transmission_en.ts transmission_ru.ts
FORMS += mainwin.ui
RESOURCES += application.qrc
SOURCES += about.cc app.cc dbus-adaptor.cc details.cc file-tree.cc filters.cc \
formatter.cc hig.cc license.cc mainwin.cc make-dialog.cc options.cc \
prefs.cc prefs-dialog.cc qticonloader.cc relocate.cc session.cc \
session-dialog.cc squeezelabel.cc stats-dialog.cc torrent.cc \
torrent-delegate.cc torrent-delegate-min.cc torrent-filter.cc \
torrent-model.cc triconpushbutton.cc utils.cc watchdir.cc
SOURCES += about.cc app.cc dbus-adaptor.cc details.cc favicon.cc file-tree.cc \
filters.cc formatter.cc hig.cc license.cc mainwin.cc \
make-dialog.cc options.cc prefs.cc prefs-dialog.cc qticonloader.cc \
relocate.cc session.cc session-dialog.cc squeezelabel.cc \
stats-dialog.cc torrent.cc torrent-delegate.cc \
torrent-delegate-min.cc torrent-filter.cc torrent-model.cc \
triconpushbutton.cc utils.cc watchdir.cc
HEADERS += $$replace(SOURCES, .cc, .h)
HEADERS += speed.h types.h

View File

@ -19,6 +19,7 @@
#include <QSet>
#include <QString>
#include <QStyle>
#include <QUrl>
#include <QVariant>
#include <libtransmission/transmission.h>
@ -543,9 +544,12 @@ Torrent :: update( tr_benc * d )
int i = 0;
QStringList list;
tr_benc * child;
while(( child = tr_bencListChild( trackers, i++ )))
if( tr_bencDictFindStr( child, "announce", &str ))
while(( child = tr_bencListChild( trackers, i++ ))) {
if( tr_bencDictFindStr( child, "announce", &str )) {
dynamic_cast<MyApp*>(QApplication::instance())->favicons.add( QUrl(str) );
list.append( QString::fromUtf8( str ) );
}
}
if( myValues[TRACKERS] != list ) {
myValues[TRACKERS].setValue( list );
changed = true;