/***************************************************************************
* Copyright ( C ) 2003 by S <EFBFBD> astien Laot *
* slaout @ linux62 . org *
* *
* 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 . *
* *
* This program is distributed in the hope that it will be useful , *
* but WITHOUT ANY WARRANTY ; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the *
* GNU General Public License for more details . *
* *
* You should have received a copy of the GNU General Public License *
* along with this program ; if not , write to the *
* Free Software Foundation , Inc . , *
* 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA . *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <kurl.h>
# include <kglobal.h>
# include <kstandarddirs.h>
# include <ksimpleconfig.h>
# include <tqpainter.h>
# include <tqdir.h>
# include <tqimage.h>
# include <iostream>
# include "backgroundmanager.h"
/** class BackgroundEntry: */
BackgroundEntry : : BackgroundEntry ( const TQString & location )
{
this - > location = location ;
name = KURL ( location ) . fileName ( ) ;
tiled = false ;
pixmap = 0 ;
preview = 0 ;
customersCount = 0 ;
}
BackgroundEntry : : ~ BackgroundEntry ( )
{
delete pixmap ;
delete preview ;
}
/** class OpaqueBackgroundEntry: */
OpaqueBackgroundEntry : : OpaqueBackgroundEntry ( const TQString & name , const TQColor & color )
{
this - > name = name ;
this - > color = color ;
pixmap = 0 ;
customersCount = 0 ;
}
OpaqueBackgroundEntry : : ~ OpaqueBackgroundEntry ( )
{
delete pixmap ;
}
/** class BackgroundManager: */
BackgroundManager : : BackgroundManager ( )
{
/// std::cout << "BackgroundManager: Found the following background images in ";
TQStringList directories = KGlobal : : dirs ( ) - > resourceDirs ( " data " ) ; // eg. { "/home/seb/.kde/share/apps/", "/usr/share/apps/" }
// For each folder:
for ( TQStringList : : Iterator it = directories . begin ( ) ; it ! = directories . end ( ) ; + + it ) {
// For each file in those directories:
TQDir dir ( * it + " basket/backgrounds/ " , /*nameFilder=*/ " *.png " , /*sortSpec=*/ TQDir : : Name | TQDir : : IgnoreCase , /*filterSpec=*/ TQDir : : Files | TQDir : : NoSymLinks ) ;
/// std::cout << *it + "basket/backgrounds/ ";
TQStringList files = dir . entryList ( ) ;
for ( TQStringList : : Iterator it2 = files . begin ( ) ; it2 ! = files . end ( ) ; + + it2 ) // TODO: If an image name is present in two folders?
addImage ( * it + " basket/backgrounds/ " + * it2 ) ;
}
/// std::cout << ":" << std::endl;
/// for (BackgroundsList::Iterator it = m_backgroundsList.begin(); it != m_backgroundsList.end(); ++it)
/// std::cout << "* " << (*it)->location << " [ref: " << (*it)->name << "]" << std::endl;
connect ( & m_garbageTimer , TQT_SIGNAL ( timeout ( ) ) , this , TQT_SLOT ( doGarbage ( ) ) ) ;
}
BackgroundManager : : ~ BackgroundManager ( )
{
}
void BackgroundManager : : addImage ( const TQString & fullPath )
{
m_backgroundsList . append ( new BackgroundEntry ( fullPath ) ) ;
}
BackgroundEntry * BackgroundManager : : backgroundEntryFor ( const TQString & image )
{
for ( BackgroundsList : : Iterator it = m_backgroundsList . begin ( ) ; it ! = m_backgroundsList . end ( ) ; + + it )
if ( ( * it ) - > name = = image )
return * it ;
return 0 ;
}
OpaqueBackgroundEntry * BackgroundManager : : opaqueBackgroundEntryFor ( const TQString & image , const TQColor & color )
{
for ( OpaqueBackgroundsList : : Iterator it = m_opaqueBackgroundsList . begin ( ) ; it ! = m_opaqueBackgroundsList . end ( ) ; + + it )
if ( ( * it ) - > name = = image & & ( * it ) - > color = = color )
return * it ;
return 0 ;
}
bool BackgroundManager : : subscribe ( const TQString & image )
{
BackgroundEntry * entry = backgroundEntryFor ( image ) ;
if ( entry ) {
// If it's the first time something subscribe to this image:
if ( ! entry - > pixmap ) {
// Try to load the pixmap:
entry - > pixmap = new TQPixmap ( entry - > location ) ;
// Try to figure out if it's a tiled background image or not (default to NO):
KSimpleConfig config ( entry - > location + " .config " , /*readOnly=*/ true ) ;
config . setGroup ( " BasKet Background Image Configuration " ) ;
entry - > tiled = config . readBoolEntry ( " tiled " , false ) ;
}
// Return if the image loading has failed:
if ( entry - > pixmap - > isNull ( ) ) {
/// std::cout << "BackgroundManager: Failed to load " << entry->location << std::endl;
return false ;
}
// Success: effectively subscribe:
+ + entry - > customersCount ;
return true ;
} else {
// Don't exist: subscription failed:
/// std::cout << "BackgroundManager: Requested unexisting image: " << image << std::endl;
return false ;
}
}
bool BackgroundManager : : subscribe ( const TQString & image , const TQColor & color )
{
BackgroundEntry * backgroundEntry = backgroundEntryFor ( image ) ;
// First, if the image doesn't exist, isn't subscribed, or failed to load then we don't go further:
if ( ! backgroundEntry | | ! backgroundEntry - > pixmap | | backgroundEntry - > pixmap - > isNull ( ) ) {
/// std::cout << "BackgroundManager: Requested an unexisting or unsubscribed image: (" << image << "," << color.name() << ")..." << std::endl;
return false ;
}
OpaqueBackgroundEntry * opaqueBackgroundEntry = opaqueBackgroundEntryFor ( image , color ) ;
// If this couple is requested for the first time or it haven't been subscribed for a long time enough, create it:
if ( ! opaqueBackgroundEntry ) {
/// std::cout << "BackgroundManager: Computing (" << image << "," << color.name() << ")..." << std::endl;
opaqueBackgroundEntry = new OpaqueBackgroundEntry ( image , color ) ;
opaqueBackgroundEntry - > pixmap = new TQPixmap ( backgroundEntry - > pixmap - > size ( ) ) ;
opaqueBackgroundEntry - > pixmap - > fill ( color ) ;
TQPainter painter ( opaqueBackgroundEntry - > pixmap ) ;
painter . drawPixmap ( 0 , 0 , * ( backgroundEntry - > pixmap ) ) ;
painter . end ( ) ;
m_opaqueBackgroundsList . append ( opaqueBackgroundEntry ) ;
}
// We are now sure the entry exist, do the subscription:
+ + opaqueBackgroundEntry - > customersCount ;
return true ;
}
void BackgroundManager : : unsubscribe ( const TQString & image )
{
BackgroundEntry * entry = backgroundEntryFor ( image ) ;
if ( ! entry ) {
/// std::cout << "BackgroundManager: Wanted to unsuscribe a not subscribed image: " << image << std::endl;
return ;
}
- - entry - > customersCount ;
if ( entry - > customersCount < = 0 )
requestDelayedGarbage ( ) ;
}
void BackgroundManager : : unsubscribe ( const TQString & image , const TQColor & color )
{
OpaqueBackgroundEntry * entry = opaqueBackgroundEntryFor ( image , color ) ;
if ( ! entry ) {
/// std::cout << "BackgroundManager: Wanted to unsuscribe a not subscribed colored image: (" << image << "," << color.name() << ")" << std::endl;
return ;
}
- - entry - > customersCount ;
if ( entry - > customersCount < = 0 )
requestDelayedGarbage ( ) ;
}
TQPixmap * BackgroundManager : : pixmap ( const TQString & image )
{
BackgroundEntry * entry = backgroundEntryFor ( image ) ;
if ( ! entry | | ! entry - > pixmap | | entry - > pixmap - > isNull ( ) ) {
/// std::cout << "BackgroundManager: Requested an unexisting or unsubscribed image: " << image << std::endl;
return 0 ;
}
return entry - > pixmap ;
}
TQPixmap * BackgroundManager : : opaquePixmap ( const TQString & image , const TQColor & color )
{
OpaqueBackgroundEntry * entry = opaqueBackgroundEntryFor ( image , color ) ;
if ( ! entry | | ! entry - > pixmap | | entry - > pixmap - > isNull ( ) ) {
/// std::cout << "BackgroundManager: Requested an unexisting or unsubscribed colored image: (" << image << "," << color.name() << ")" << std::endl;
return 0 ;
}
return entry - > pixmap ;
}
bool BackgroundManager : : tiled ( const TQString & image )
{
BackgroundEntry * entry = backgroundEntryFor ( image ) ;
if ( ! entry | | ! entry - > pixmap | | entry - > pixmap - > isNull ( ) ) {
/// std::cout << "BackgroundManager: Requested an unexisting or unsubscribed image: " << image << std::endl;
return false ;
}
return entry - > tiled ;
}
bool BackgroundManager : : exists ( const TQString & image )
{
for ( BackgroundsList : : iterator it = m_backgroundsList . begin ( ) ; it ! = m_backgroundsList . end ( ) ; + + it )
if ( ( * it ) - > name = = image )
return true ;
return false ;
}
TQStringList BackgroundManager : : imageNames ( )
{
TQStringList list ;
for ( BackgroundsList : : iterator it = m_backgroundsList . begin ( ) ; it ! = m_backgroundsList . end ( ) ; + + it )
list . append ( ( * it ) - > name ) ;
return list ;
}
TQPixmap * BackgroundManager : : preview ( const TQString & image )
{
static const int MAX_WIDTH = 100 ;
static const int MAX_HEIGHT = 75 ;
static const TQColor PREVIEW_BG = TQt : : white ;
BackgroundEntry * entry = backgroundEntryFor ( image ) ;
if ( ! entry ) {
/// std::cout << "BackgroundManager: Requested the preview of an unexisting image: " << image << std::endl;
return false ;
}
// The easiest way: already computed:
if ( entry - > preview )
return entry - > preview ;
// Then, try to load the preview from file:
TQString previewPath = KGlobal : : dirs ( ) - > findResource ( " data " , " basket/backgrounds/previews/ " + entry - > name ) ;
TQPixmap * previewPixmap = new TQPixmap ( previewPath ) ;
// Success:
if ( ! previewPixmap - > isNull ( ) ) {
/// std::cout << "BackgroundManager: Loaded image preview for " << entry->location << " from file " << previewPath << std::endl;
entry - > preview = previewPixmap ;
return entry - > preview ;
}
// We failed? Then construct it:
// Note: if a preview is requested, it's because the user is currently choosing an image.
// Since we need that image to create the preview, we keep the image in memory.
// Then, it will already be loaded when user press [OK] in the background image chooser.
// BUT we also delay a garbage because we don't want EVERY images to be loaded if the user use only a few of them, of course:
// Already used? Good: we don't have to load it...
if ( ! entry - > pixmap ) {
// Note: it's a code duplication from BackgroundManager::subscribe(const TQString &image),
// Because, as we are loading the pixmap we ALSO need to know if it's a tile or not, in case that image will soon be used (and not destroyed by the garbager):
entry - > pixmap = new TQPixmap ( entry - > location ) ;
// Try to figure out if it's a tiled background image or not (default to NO):
KSimpleConfig config ( entry - > location + " .config " , /*readOnly=*/ true ) ;
config . setGroup ( " BasKet Background Image Configuration " ) ;
entry - > tiled = config . readBoolEntry ( " tiled " , false ) ;
}
// The image cannot be loaded, we failed:
if ( entry - > pixmap - > isNull ( ) )
return 0 ;
// Good that we are still alive: entry->pixmap contains the pixmap to rescale down for the preview:
// Compute new size:
int width = entry - > pixmap - > width ( ) ;
int height = entry - > pixmap - > height ( ) ;
if ( width > MAX_WIDTH ) {
height = height * MAX_WIDTH / width ;
width = MAX_WIDTH ;
}
if ( height > MAX_HEIGHT ) {
width = width * MAX_HEIGHT / height ;
height = MAX_HEIGHT ;
}
// And create the resulting pixmap:
TQPixmap * result = new TQPixmap ( width , height ) ;
result - > fill ( PREVIEW_BG ) ;
TQImage imageToScale = entry - > pixmap - > convertToImage ( ) ;
TQPixmap pmScaled ;
pmScaled . convertFromImage ( imageToScale . smoothScale ( width , height ) ) ;
TQPainter painter ( result ) ;
painter . drawPixmap ( 0 , 0 , pmScaled ) ;
painter . end ( ) ;
// Saving it to file for later:
TQString folder = KGlobal : : dirs ( ) - > saveLocation ( " data " , " basket/backgrounds/previews/ " ) ;
result - > save ( folder + entry - > name , " PNG " ) ;
// Ouf! That's done:
entry - > preview = result ;
requestDelayedGarbage ( ) ;
return entry - > preview ;
}
TQString BackgroundManager : : pathForImageName ( const TQString & image )
{
BackgroundEntry * entry = backgroundEntryFor ( image ) ;
if ( entry = = 0 )
return " " ;
else
return entry - > location ;
}
TQString BackgroundManager : : previewPathForImageName ( const TQString & image )
{
BackgroundEntry * entry = backgroundEntryFor ( image ) ;
if ( entry = = 0 )
return " " ;
else {
TQString previewPath = KGlobal : : dirs ( ) - > findResource ( " data " , " basket/backgrounds/previews/ " + entry - > name ) ;
TQDir dir ;
if ( ! dir . exists ( previewPath ) )
return " " ;
else
return previewPath ;
}
}
void BackgroundManager : : requestDelayedGarbage ( )
{
static const int DELAY = 60 /*seconds*/ ;
if ( ! m_garbageTimer . isActive ( ) )
m_garbageTimer . start ( DELAY * 1000 /*ms*/ , /*singleShot=*/ true ) ;
}
void BackgroundManager : : doGarbage ( )
{
/// std::cout << "BackgroundManager: Doing garbage..." << std::endl;
/// std::cout << "BackgroundManager: Images:" << std::endl;
for ( BackgroundsList : : Iterator it = m_backgroundsList . begin ( ) ; it ! = m_backgroundsList . end ( ) ; + + it ) {
BackgroundEntry * entry = * it ;
/// std::cout << "* " << entry->name << ": used " << entry->customersCount << " times";
if ( entry - > customersCount < = 0 & & entry - > pixmap ) {
/// std::cout << " [Deleted cached pixmap]";
delete entry - > pixmap ;
entry - > pixmap = 0 ;
}
/// std::cout << std::endl;
}
/// std::cout << "BackgroundManager: Opaque Cached Images:" << std::endl;
for ( OpaqueBackgroundsList : : Iterator it = m_opaqueBackgroundsList . begin ( ) ; it ! = m_opaqueBackgroundsList . end ( ) ; ) {
OpaqueBackgroundEntry * entry = * it ;
/// std::cout << "* " << entry->name << "," << entry->color.name() << ": used " << entry->customersCount << " times";
if ( entry - > customersCount < = 0 ) {
/// std::cout << " [Deleted entry]";
delete entry - > pixmap ;
entry - > pixmap = 0 ;
it = m_opaqueBackgroundsList . remove ( it ) ;
} else
+ + it ;
/// std::cout << std::endl;
}
}
# include "backgroundmanager.moc"