1 /***************************************************************************
2 * Copyright (C) 2003 by S�astien Laot *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
23 #include <kstandarddirs.h>
24 #include <ksimpleconfig.h>
33 #include "backgroundmanager.h"
35 /** class BackgroundEntry: */
37 BackgroundEntry::BackgroundEntry(const QString
&location
)
39 this->location
= location
;
40 name
= KURL(location
).fileName();
47 BackgroundEntry::~BackgroundEntry()
53 /** class OpaqueBackgroundEntry: */
55 OpaqueBackgroundEntry::OpaqueBackgroundEntry(const QString
&name
, const QColor
&color
)
63 OpaqueBackgroundEntry::~OpaqueBackgroundEntry()
68 /** class BackgroundManager: */
70 BackgroundManager::BackgroundManager()
72 /// std::cout << "BackgroundManager: Found the following background images in ";
73 QStringList directories
= KGlobal::dirs()->resourceDirs("data"); // eg. { "/home/seb/.kde/share/apps/", "/usr/share/apps/" }
75 for (QStringList::Iterator it
= directories
.begin(); it
!= directories
.end(); ++it
) {
76 // For each file in those directories:
77 QDir
dir(*it
+ "basket/backgrounds/", /*nameFilder=*/"*.png", /*sortSpec=*/QDir::Name
| QDir::IgnoreCase
, /*filterSpec=*/QDir::Files
| QDir::NoSymLinks
);
78 /// std::cout << *it + "basket/backgrounds/ ";
79 QStringList files
= dir
.entryList();
80 for (QStringList::Iterator it2
= files
.begin(); it2
!= files
.end(); ++it2
) // TODO: If an image name is present in two folders?
81 addImage(*it
+ "basket/backgrounds/" + *it2
);
84 /// std::cout << ":" << std::endl;
85 /// for (BackgroundsList::Iterator it = m_backgroundsList.begin(); it != m_backgroundsList.end(); ++it)
86 /// std::cout << "* " << (*it)->location << " [ref: " << (*it)->name << "]" << std::endl;
88 connect( &m_garbageTimer
, SIGNAL(timeout()), this, SLOT(doGarbage()) );
91 BackgroundManager::~BackgroundManager()
95 void BackgroundManager::addImage(const QString
&fullPath
)
97 m_backgroundsList
.append(new BackgroundEntry(fullPath
));
100 BackgroundEntry
* BackgroundManager::backgroundEntryFor(const QString
&image
)
102 for (BackgroundsList::Iterator it
= m_backgroundsList
.begin(); it
!= m_backgroundsList
.end(); ++it
)
103 if ((*it
)->name
== image
)
108 OpaqueBackgroundEntry
* BackgroundManager::opaqueBackgroundEntryFor(const QString
&image
, const QColor
&color
)
110 for (OpaqueBackgroundsList::Iterator it
= m_opaqueBackgroundsList
.begin(); it
!= m_opaqueBackgroundsList
.end(); ++it
)
111 if ((*it
)->name
== image
&& (*it
)->color
== color
)
116 bool BackgroundManager::subscribe(const QString
&image
)
118 BackgroundEntry
*entry
= backgroundEntryFor(image
);
120 // If it's the first time something subscribe to this image:
121 if (!entry
->pixmap
) {
122 // Try to load the pixmap:
123 entry
->pixmap
= new QPixmap(entry
->location
);
124 // Try to figure out if it's a tiled background image or not (default to NO):
125 KSimpleConfig
config(entry
->location
+ ".config", /*readOnly=*/true);
126 config
.setGroup("BasKet Background Image Configuration");
127 entry
->tiled
= config
.readBoolEntry("tiled", false);
129 // Return if the image loading has failed:
130 if (entry
->pixmap
->isNull()) {
131 /// std::cout << "BackgroundManager: Failed to load " << entry->location << std::endl;
134 // Success: effectively subscribe:
135 ++entry
->customersCount
;
138 // Don't exist: subscription failed:
139 /// std::cout << "BackgroundManager: Requested unexisting image: " << image << std::endl;
144 bool BackgroundManager::subscribe(const QString
&image
, const QColor
&color
)
146 BackgroundEntry
*backgroundEntry
= backgroundEntryFor(image
);
148 // First, if the image doesn't exist, isn't subscribed, or failed to load then we don't go further:
149 if (!backgroundEntry
|| !backgroundEntry
->pixmap
|| backgroundEntry
->pixmap
->isNull()) {
150 /// std::cout << "BackgroundManager: Requested an unexisting or unsubscribed image: (" << image << "," << color.name() << ")..." << std::endl;
154 OpaqueBackgroundEntry
*opaqueBackgroundEntry
= opaqueBackgroundEntryFor(image
, color
);
156 // If this couple is requested for the first time or it haven't been subscribed for a long time enough, create it:
157 if (!opaqueBackgroundEntry
) {
158 /// std::cout << "BackgroundManager: Computing (" << image << "," << color.name() << ")..." << std::endl;
159 opaqueBackgroundEntry
= new OpaqueBackgroundEntry(image
, color
);
160 opaqueBackgroundEntry
->pixmap
= new QPixmap(backgroundEntry
->pixmap
->size());
161 opaqueBackgroundEntry
->pixmap
->fill(color
);
162 QPainter
painter(opaqueBackgroundEntry
->pixmap
);
163 painter
.drawPixmap(0, 0, *(backgroundEntry
->pixmap
));
165 m_opaqueBackgroundsList
.append(opaqueBackgroundEntry
);
168 // We are now sure the entry exist, do the subscription:
169 ++opaqueBackgroundEntry
->customersCount
;
173 void BackgroundManager::unsubscribe(const QString
&image
)
175 BackgroundEntry
*entry
= backgroundEntryFor(image
);
178 /// std::cout << "BackgroundManager: Wanted to unsuscribe a not subscribed image: " << image << std::endl;
182 --entry
->customersCount
;
183 if (entry
->customersCount
<= 0)
184 requestDelayedGarbage();
187 void BackgroundManager::unsubscribe(const QString
&image
, const QColor
&color
)
189 OpaqueBackgroundEntry
*entry
= opaqueBackgroundEntryFor(image
, color
);
192 /// std::cout << "BackgroundManager: Wanted to unsuscribe a not subscribed colored image: (" << image << "," << color.name() << ")" << std::endl;
196 --entry
->customersCount
;
197 if (entry
->customersCount
<= 0)
198 requestDelayedGarbage();
201 QPixmap
* BackgroundManager::pixmap(const QString
&image
)
203 BackgroundEntry
*entry
= backgroundEntryFor(image
);
205 if (!entry
|| !entry
->pixmap
|| entry
->pixmap
->isNull()) {
206 /// std::cout << "BackgroundManager: Requested an unexisting or unsubscribed image: " << image << std::endl;
210 return entry
->pixmap
;
213 QPixmap
* BackgroundManager::opaquePixmap(const QString
&image
, const QColor
&color
)
215 OpaqueBackgroundEntry
*entry
= opaqueBackgroundEntryFor(image
, color
);
217 if (!entry
|| !entry
->pixmap
|| entry
->pixmap
->isNull()) {
218 /// std::cout << "BackgroundManager: Requested an unexisting or unsubscribed colored image: (" << image << "," << color.name() << ")" << std::endl;
222 return entry
->pixmap
;
225 bool BackgroundManager::tiled(const QString
&image
)
227 BackgroundEntry
*entry
= backgroundEntryFor(image
);
229 if (!entry
|| !entry
->pixmap
|| entry
->pixmap
->isNull()) {
230 /// std::cout << "BackgroundManager: Requested an unexisting or unsubscribed image: " << image << std::endl;
237 bool BackgroundManager::exists(const QString
&image
)
239 for (BackgroundsList::iterator it
= m_backgroundsList
.begin(); it
!= m_backgroundsList
.end(); ++it
)
240 if ((*it
)->name
== image
)
245 QStringList
BackgroundManager::imageNames()
248 for (BackgroundsList::iterator it
= m_backgroundsList
.begin(); it
!= m_backgroundsList
.end(); ++it
)
249 list
.append((*it
)->name
);
253 QPixmap
* BackgroundManager::preview(const QString
&image
)
255 static const int MAX_WIDTH
= 100;
256 static const int MAX_HEIGHT
= 75;
257 static const QColor PREVIEW_BG
= Qt::white
;
259 BackgroundEntry
*entry
= backgroundEntryFor(image
);
262 /// std::cout << "BackgroundManager: Requested the preview of an unexisting image: " << image << std::endl;
266 // The easiest way: already computed:
268 return entry
->preview
;
270 // Then, try to load the preview from file:
271 QString previewPath
= KGlobal::dirs()->findResource("data", "basket/backgrounds/previews/" + entry
->name
);
272 QPixmap
*previewPixmap
= new QPixmap(previewPath
);
274 if (!previewPixmap
->isNull()) {
275 /// std::cout << "BackgroundManager: Loaded image preview for " << entry->location << " from file " << previewPath << std::endl;
276 entry
->preview
= previewPixmap
;
277 return entry
->preview
;
280 // We failed? Then construct it:
281 // Note: if a preview is requested, it's because the user is currently choosing an image.
282 // Since we need that image to create the preview, we keep the image in memory.
283 // Then, it will already be loaded when user press [OK] in the background image chooser.
284 // 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:
286 // Already used? Good: we don't have to load it...
287 if (!entry
->pixmap
) {
288 // Note: it's a code duplication from BackgroundManager::subscribe(const QString &image),
289 // 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):
290 entry
->pixmap
= new QPixmap(entry
->location
);
291 // Try to figure out if it's a tiled background image or not (default to NO):
292 KSimpleConfig
config(entry
->location
+ ".config", /*readOnly=*/true);
293 config
.setGroup("BasKet Background Image Configuration");
294 entry
->tiled
= config
.readBoolEntry("tiled", false);
297 // The image cannot be loaded, we failed:
298 if (entry
->pixmap
->isNull())
301 // Good that we are still alive: entry->pixmap contains the pixmap to rescale down for the preview:
303 int width
= entry
->pixmap
->width();
304 int height
= entry
->pixmap
->height();
305 if (width
> MAX_WIDTH
) {
306 height
= height
* MAX_WIDTH
/ width
;
309 if (height
> MAX_HEIGHT
) {
310 width
= width
* MAX_HEIGHT
/ height
;
313 // And create the resulting pixmap:
314 QPixmap
*result
= new QPixmap(width
, height
);
315 result
->fill(PREVIEW_BG
);
316 QImage imageToScale
= entry
->pixmap
->convertToImage();
318 pmScaled
.convertFromImage(imageToScale
.smoothScale(width
, height
));
319 QPainter
painter(result
);
320 painter
.drawPixmap(0, 0, pmScaled
);
323 // Saving it to file for later:
324 QString folder
= KGlobal::dirs()->saveLocation("data", "basket/backgrounds/previews/");
325 result
->save(folder
+ entry
->name
, "PNG");
328 entry
->preview
= result
;
329 requestDelayedGarbage();
330 return entry
->preview
;
333 QString
BackgroundManager::pathForImageName(const QString
&image
)
335 BackgroundEntry
*entry
= backgroundEntryFor(image
);
339 return entry
->location
;
342 QString
BackgroundManager::previewPathForImageName(const QString
&image
)
344 BackgroundEntry
*entry
= backgroundEntryFor(image
);
348 QString previewPath
= KGlobal::dirs()->findResource("data", "basket/backgrounds/previews/" + entry
->name
);
350 if (!dir
.exists(previewPath
))
357 void BackgroundManager::requestDelayedGarbage()
359 static const int DELAY
= 60/*seconds*/;
361 if (!m_garbageTimer
.isActive())
362 m_garbageTimer
.start(DELAY
* 1000/*ms*/, /*singleShot=*/true);
365 void BackgroundManager::doGarbage()
367 /// std::cout << "BackgroundManager: Doing garbage..." << std::endl;
369 /// std::cout << "BackgroundManager: Images:" << std::endl;
370 for (BackgroundsList::Iterator it
= m_backgroundsList
.begin(); it
!= m_backgroundsList
.end(); ++it
) {
371 BackgroundEntry
*entry
= *it
;
372 /// std::cout << "* " << entry->name << ": used " << entry->customersCount << " times";
373 if (entry
->customersCount
<= 0 && entry
->pixmap
) {
374 /// std::cout << " [Deleted cached pixmap]";
375 delete entry
->pixmap
;
378 /// std::cout << std::endl;
381 /// std::cout << "BackgroundManager: Opaque Cached Images:" << std::endl;
382 for (OpaqueBackgroundsList::Iterator it
= m_opaqueBackgroundsList
.begin(); it
!= m_opaqueBackgroundsList
.end(); ) {
383 OpaqueBackgroundEntry
*entry
= *it
;
384 /// std::cout << "* " << entry->name << "," << entry->color.name() << ": used " << entry->customersCount << " times";
385 if (entry
->customersCount
<= 0) {
386 /// std::cout << " [Deleted entry]";
387 delete entry
->pixmap
;
389 it
= m_opaqueBackgroundsList
.remove(it
);
392 /// std::cout << std::endl;
396 #include "backgroundmanager.moc"