Logo Search packages:      
Sourcecode: kmess version File versions  Download package

thumbnailprovider.cpp

/***************************************************************************
                          thumbnailprovider.cpp -  description
                             -------------------
    begin                : Sun Jan 21 2007
    copyright            : (C) 2007 by Pedro Ferreira
                           (C) 2007 by Diederik van der Boor
    email                : pedro.ferreira@fe.up.pt
                           "vdboor" --at-- "codingdomain.com"
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include "thumbnailprovider.h"

#include "kmessdebug.h"

#include <kurl.h>
#include <kmimetype.h>
#include <kiconloader.h>
#include <kio/previewjob.h>

#include <qstylesheet.h>
#include <qtimer.h>
#include <kmdcodec.h>

#include <string.h>  // for memset()


/**
 * @brief The constructor
 *
 * Starts a KIO::PreviewJob to get the preview.
 * When the job completed or failed, gotResult() is fired.
 *
 * @param  fileName  Name of the file to request.
 * @param  size      Size of the thumbnails. Windows Live Messenger also uses 96x96 thumbnails for all files.
 *                   Depending on it's "file preview size" setting, it scales the received images down afterwards.
 * @param  fallback  Whether to return a fallback icon instead. This is a generic file type icon also used in the Konqueror.
 */
00047 ThumbnailProvider::ThumbnailProvider( const QString &fileName, int size )
: QObject( 0, "ThumbnailProvider" )
, fileName_( fileName )
, resultError_( false )
, size_( size )
{
#ifdef KMESSDEBUG_THUMBNAILPROVIDER
  kdDebug() << "ThumbnailProvider: requesting thumbnail for" << fileName << endl;
#endif

  // The quick method (also displays a transfer dialog):
  // KIO::NetAccess::download( "thumbnail://" + fileName, tempFile, 0 )
  // thumbnailImage_ = QImage( tempFile );
  // KIO::NetAccess::removeTempFile( tempFile );


  // The complex (but async) method:
  // Wrap file in a file list, use KIO::PreviewJob
  KURL url( fileName );
  fileList_ = KURL::List( url );

  // Remove preview for text files
  // TODO: preview should work, but doesn't
  enabledPlugins_ = KIO::PreviewJob::availablePlugins();
  enabledPlugins_.remove( "textthumbnail" );

#ifdef KMESSDEBUG_THUMBNAILPROVIDER
  kdDebug() << "ThumbnailProvider: enabled preview plugins: " << enabledPlugins_ << endl;
#endif

  // Get file type
  KMimeType::Ptr type = KMimeType::findByURL( url );

#ifdef KMESSDEBUG_THUMBNAILPROVIDER
  kdDebug() << "ThumbnailProvider: file mime type '" << type->name() << "'" << endl;
#endif

  // For some file types, don't generate a preview
  // TODO: improve, files like .h and .cpp have a different mime type.
  if( type->name() == "text/plain" )
  {
#ifdef KMESSDEBUG_THUMBNAILPROVIDER
    kdDebug() << "ThumbnailProvider: not creating previews for this file type." << endl;
#endif
    // Make slot call delayed, so clients can still connect to signals first.
    QTimer::singleShot( 0, this, SLOT(slotFailed()) );
    return;
  }

  // Create the preview job
  KIO::PreviewJob *previewJob = KIO::filePreview( fileList_, size, size,
                                                  100,   // 100% alpha
                                                  true,  // scale (default value)
                                                  true,  // save (default value)
                                                  &enabledPlugins_ );

  // Connect signals.
  connect( previewJob, SIGNAL(      gotPreview(const KFileItem*, const QPixmap&) ),
           this,         SLOT(  slotGotPreview(const KFileItem*, const QPixmap&) ));
  connect( previewJob, SIGNAL(          failed(const KFileItem*) ),
           this,         SLOT(      slotFailed(const KFileItem*) ));

  // The KIO::PreviewJob auto deletes itself.
}



/**
 * @brief Indicate whether a thumbnail was created.
 */
00117 bool ThumbnailProvider::isSuccessful() const
{
  return ! resultError_;
}



/**
 * @brief Return the generated image as byte array.
 */
00127 const QByteArray &ThumbnailProvider::getData() const
{
  return thumbnailData_;
}



/**
 * @brief Generate the fallback image.
 *
 * This can be called when isSuccessful() returns false.
 * It overwrites the internal image, so it can be requested with getData() and getImage().
 */
00140 void ThumbnailProvider::generateFallbackImage()
{
  QString      iconTitle = KMimeType::iconForURL( KURL( fileName_ ) );
  KIconLoader *loader    = KGlobal::iconLoader();
  QString      iconPath  = loader->iconPath( iconTitle, -size_, false );
  storeImage( QImage( iconPath ) );
}



/**
 * @brief Return the generated image.
 */
00153 const QImage &ThumbnailProvider::getImage() const
{
  return thumbnailImage_;
}



/**
 * Return the HTML image tag.
 */
00163 QString ThumbnailProvider::getImageTag( const QString &altText ) const
{
  if( thumbnailData_.isNull() || thumbnailImage_.isNull() )
  {
    return QString::null;
  }

  QString previewData = KCodecs::base64Encode( thumbnailData_ );
  return "<img src=\"data:image/png;base64," + previewData + "\""
         " width=\""  + QString::number( thumbnailImage_.width() )  + "\""
         " height=\"" + QString::number( thumbnailImage_.height() ) + "\""
         " alt=\""    + QStyleSheet::escape( altText ) + "\" />";
}



/**
 * @brief Called when a preview is available.
 */
00182 void ThumbnailProvider::slotGotPreview( const KFileItem */*fileItem*/, const QPixmap &preview )
{
#ifdef KMESSDEBUG_THUMBNAILPROVIDER
  kdDebug() << "ThumbnailProvider: thumbnail generated." << endl;
#endif

  // The KFileItem already gets deleted by KIO

  // Downloads QPixmap from the X server again to a QImage in the client memory.
  // So far this can't be avoided because KIO::PreviewJob already generates a QPixmap.
  QImage image;
  image = preview;

  // Resize canvas to square size for Windows Live Messenger.
  // This way the image is not chopped by the standard small preview size.
  if( image.width() != image.height() )
  {
    // Create square canvas with transparent background
    int size = QMAX( image.width(), image.height() );
    QImage fixedImage( size, size, 32 );
    fixedImage.setAlphaBuffer( true );
    fixedImage.fill( qRgba( 0xff, 0xff, 0xff, 0xff ) );  // white transparent.

    // Qt bug: the fill() works in stand-alone apps, but not here.
    // Found at openSUSE, Qt 3.3.8, KDE 3.5.6. The following the scanlines with the same color.
    memset( fixedImage.bits(), 0, size * size * 4 );

    /*
    uint **imageBits = (uint**) fixedImage.jumpTable();
    for( int y = 0; y < fixedImage.height(); y++ )
    {
      uint *scanLine = (uint*) imageBits[y];
      for( int x = 0; x < fixedImage.width(); x++ )
      {
        scanLine[x] = 0;
      }
    }
    */

    // Copy image data centered in new image.
    bitBlt( &fixedImage, ( size - image.width() ) / 2, ( size - image.height() ) / 2,  // dest, dx, dy
            &image, 0, 0, -1, -1, 0 );  // src, x, y, width, height, conversion_flags

    storeImage( fixedImage );
  }
  else
  {
    storeImage( image );
  }

  // Store and emit result
  emit gotResult();
}



/**
 * @brief Called when a preview could not be generated.
 */
00241 void ThumbnailProvider::slotFailed( const KFileItem */*fileItem*/ )
{
#ifdef KMESSDEBUG_THUMBNAILPROVIDER
  kdDebug() << "ThumbnailProvider: thumbnail could not be generated." << endl;
#endif

  // The KFileItem already gets deleted by KIO
  // Note that the contructor currently can call slotFailed(0).

  // No file name, get generic file icon instead.
  resultError_ = true;
  emit gotResult();
}



/**
 * @brief Store the image in the instance fields.
 */
00260 void ThumbnailProvider::storeImage( const QImage &image )
{
  // Set state
  resultError_    = false;
  thumbnailImage_ = image;

  // Scale down if needed. Don't scale large images up
  // The client may scale the image down though depending on the settings.
  if( thumbnailImage_.width() > size_ || thumbnailImage_.height() > size_ )
  {
    thumbnailImage_ = thumbnailImage_.smoothScale( size_, size_, QImage::ScaleMin );
  }

  // Also save as PNG data for the file transfers.
  QBuffer buffer( thumbnailData_ );
  buffer.open( IO_WriteOnly );
  thumbnailImage_.save( &buffer, "PNG" );
}



#include "thumbnailprovider.moc"

Generated by  Doxygen 1.6.0   Back to index