|
|
/***************************************************************************
|
|
|
* Copyright (C) 2003 by S<>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 <tdeglobal.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 = TDEGlobal::dirs()->resourceDirs("data"); // eg. { "/home/seb/.trinity/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 0;
|
|
|
}
|
|
|
|
|
|
// The easiest way: already computed:
|
|
|
if (entry->preview)
|
|
|
return entry->preview;
|
|
|
|
|
|
// Then, try to load the preview from file:
|
|
|
TQString previewPath = TDEGlobal::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 = TDEGlobal::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 = TDEGlobal::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"
|