OSDN Git Service

10abad5a84237c5be6317238b7be81bcfb433965
[kita/kita.git] / kita / src / libkita / imgmanager.cpp
1 /***************************************************************************
2 *   Copyright (C) 2004 by Kita Developers                                 *
3 *   ikemo@users.sourceforge.jp                                            *
4 *                                                                         *
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.                                   *
9 ***************************************************************************/
10
11 /* Image Manager class */
12
13 #include "imgmanager.h"
14 #include "cache.h"
15 #include "kitaconfig.h"
16 #include "downloadmanager.h"
17
18 #include <kdeversion.h>
19 #include <kio/netaccess.h>
20 #include <klocale.h>
21 #include <kfiledialog.h>
22 #include <kconfig.h>
23
24 #include <qregexp.h>
25 #include <qfile.h>
26 #include <qdatastream.h>
27 #include <qmessagebox.h>
28 #include <qapplication.h>
29 #include <qimage.h>
30
31 using namespace Kita;
32
33 ImgManager* ImgManager::instance = NULL;
34 QMutex ImgManager::m_mutex;
35
36 /*-----------------------------------------------------------*/
37
38
39 ImgManager::ImgManager( QWidget* mainwidget )
40 {
41     m_imgDatDict.clear();
42     m_mainwidget = mainwidget;
43     m_urlList.clear();
44 }
45
46
47 ImgManager::~ImgManager()
48 {}
49
50
51 /* call this first */ /* public */ /* static */
52 void ImgManager::setup( QWidget* mainwidget )
53 {
54     instance = new ImgManager( mainwidget );
55 }
56
57
58 /* public */ /* static */
59 void ImgManager::deleteInstance()
60 {
61     if ( instance ) delete instance;
62 }
63
64
65 /* public */ /* static */
66 ImgManager* ImgManager::getInstance()
67 {
68     return instance;
69 }
70
71
72 /* public */ /* static */
73 bool ImgManager::isImgFile( const KURL& url, bool use_mimetype )
74 {
75     return instance->isImgFilePrivate( url, use_mimetype );
76 }
77
78
79 /* public */ /* static */
80 bool ImgManager::isAnimationGIF( const KURL& url )
81 {
82     QRegExp reg_ext( ".*\\.gif$" );
83     if ( reg_ext.search( url.fileName().lower() ) != -1 ) return TRUE;
84
85     return FALSE;
86 }
87
88
89 /* public */ /* static */
90 bool ImgManager::isBMP( const KURL& url )
91 {
92     QRegExp reg_ext( ".*\\.bmp$" );
93     if ( reg_ext.search( url.fileName().lower() ) != -1 ) return TRUE;
94
95     return FALSE;
96 }
97
98
99 /* public */ /* static */
100 bool ImgManager::load( const KURL& url, const KURL& datURL )
101 {
102     QMutexLocker locker( &m_mutex );
103
104     return instance->loadPrivate( url, datURL );
105 }
106
107
108 /* public */ /* static */
109 void ImgManager::stop( const KURL& url )
110 {
111     QMutexLocker locker( &m_mutex );
112
113     DownloadManager::stopLoading( url );
114 }
115
116
117 /* public */ /* static */
118 QString ImgManager::getPath( const KURL& url )
119 {
120     return Cache::getImgPath( url );
121 }
122
123
124 /* public */ /* static */
125 bool ImgManager::isLoadingNow( const KURL& url )
126 {
127
128     return DownloadManager::isLoadingNow( url );
129 }
130
131
132 /* public */ /* static */
133 bool ImgManager::deleteCache( const KURL& url, QWidget* parent )
134 {
135     QMutexLocker locker( &m_mutex );
136
137     return instance->deleteCachePrivate( url, parent );
138 }
139
140
141 /* public */ /* static */
142 bool ImgManager::copyCache( const KURL& url, QWidget* parent )
143 {
144     QMutexLocker locker( &m_mutex );
145
146     return instance->copyCachePrivate( url, parent );
147 }
148
149
150 /* public */ /* static */
151 bool ImgManager::mosaic( const KURL& url )
152 {
153     instance->cacheExists( url ); /* to create IMGDAT if cache exists */
154
155     IMGDAT* imgdat = instance->getImgDat( url );
156     if ( !imgdat ) return TRUE;
157
158     return imgdat->mosaic;
159 }
160
161
162 /* public */ /* static */
163 void ImgManager::setMosaic( const KURL& url, bool status )
164 {
165     instance->setMosaicPrivate( url, status );
166 }
167
168
169 /* return -1 if IMGDAT doesn't exist. */  /* public */ /* static */
170 int ImgManager::code( const KURL& url )
171 {
172     instance->cacheExists( url ); /* to create IMGDAT if cache exists */
173
174     IMGDAT* imgdat = instance->getImgDat( url );
175     if ( !imgdat ) return -1;
176
177     return imgdat->code;
178 }
179
180
181 /* public */ /* static */
182 unsigned int ImgManager::size( const KURL& url )
183 {
184     instance->cacheExists( url ); /* to create IMGDAT if cache exists */
185
186     IMGDAT* imgdat = instance->getImgDat( url );
187     if ( !imgdat ) return 0;
188
189     return imgdat->size;
190 }
191
192
193 /* public */ /* static */
194 int ImgManager::width( const KURL& url )
195 {
196     instance->cacheExists( url ); /* to create IMGDAT if cache exists */
197
198     IMGDAT* imgdat = instance->getImgDat( url );
199     if ( !imgdat ) return 0;
200     if ( imgdat->width == 0 ) instance->getSize( url );
201
202     return imgdat->width;
203 }
204
205
206 /* public */ /* static */
207 int ImgManager::height( const KURL& url )
208 {
209     instance->cacheExists( url ); /* to create IMGDAT if cache exists */
210
211     IMGDAT* imgdat = instance->getImgDat( url );
212     if ( !imgdat ) return 0;
213     if ( imgdat->height == 0 ) instance->getSize( url );
214
215     return imgdat->height;
216 }
217
218
219 /* get icon pixmap */ /* public */ /* static */
220 QPixmap ImgManager::icon( const KURL& url )
221 {
222     const int iconsize = 32;
223
224     /*---------------------------*/
225
226     QPixmap pixmap;
227     QString path = Cache::getImgPath( url );
228     QImage img = QImage( path );
229     if ( img.isNull() ) return QPixmap();
230
231     pixmap.convertFromImage( img.scale( iconsize, iconsize, QImage::ScaleMin ) );
232     return pixmap;
233 }
234
235
236 /* public */ /* static */
237 KURL ImgManager::datURL( const KURL& url )
238 {
239     instance->cacheExists( url ); /* to create IMGDAT if cache exists */
240
241     IMGDAT* imgdat = instance->getImgDat( url );
242     if ( !imgdat ) return KURL();
243
244     return imgdat->datURL;
245 }
246
247
248 /*---------------------------------*/
249 /* internal functions              */
250
251
252 /* private */
253 bool ImgManager::isImgFilePrivate( const KURL& url, bool use_mimetype )
254 {
255     /* don't use mimetype      */
256     if ( !use_mimetype ) {
257
258         QStringList extlist; // = KitaConfig::imgExtList();
259         extlist = "jpg";
260         extlist += "jpeg";
261         extlist += "gif";
262         extlist += "png";
263         extlist += "bmp";
264
265         for ( QStringList::iterator it = extlist.begin(); it != extlist.end(); ++it ) {
266             QRegExp reg_ext = ".*\\." + ( *it ) + "$";
267             if ( reg_ext.search( url.fileName().lower() ) != -1 ) return TRUE;
268
269         }
270
271         return FALSE;
272     }
273
274     /*-----------------------------------*/
275
276     /* use mimetype ( very slow! )  */
277     if ( cacheExists( url ) ) return TRUE;
278
279 #if KDE_IS_VERSION( 3, 2, 0 )
280     QString mimetype = KIO::NetAccess::mimetype( url, m_mainwidget );
281 #else
282     QString mimetype = KIO::NetAccess::mimetype( url );
283 #endif
284     if ( mimetype.left( 6 ) == "image/" ) return TRUE;
285
286     return FALSE;
287 }
288
289
290 /* create new loader and start loading the image       */
291 /* when done, ImgManager emits finishImgLoad SIGNAL.   */   /* private */
292 bool ImgManager::loadPrivate( const KURL& url, const KURL& datURL )
293 {
294     const unsigned int maxload = 5; // = KitaConfig::maxLoader();
295
296     /*------------------------------*/
297     
298     if ( DownloadManager::isLoadingNow( url ) ) return FALSE;
299
300     /* cache exists? */
301     if ( cacheExists( url ) ) {
302
303         /* create EmitFinishEvent to emit finishImgLoad SIGNAL later. */
304         /* See also customEvent().                                    */
305         EmitFinishEvent * e = new EmitFinishEvent( url );
306         QApplication::postEvent( this, e );  // Qt will delete it when done
307
308         return TRUE;
309     }
310
311     if( m_urlList.count() > maxload ) return FALSE;
312     
313     QString path = Cache::getImgPath( url );
314     deleteImgDat( url );
315
316     /* create new loader, and start loading the file */
317     /* slotResult is called when done.               */
318     LoaderOption option;
319     option.usrurl = datURL;
320     FileLoader* loader = DownloadManager::download( url, path, option );
321     if ( loader == NULL ) return FALSE;
322     
323     connect( loader, SIGNAL( data( const Kita::LoaderData&, const QByteArray& ) ),
324              SLOT( slotData( const Kita::LoaderData&, const QByteArray& ) ) );
325
326     connect( loader, SIGNAL( result( const Kita::LoaderData& ) ),
327              SLOT( slotResult( const Kita::LoaderData& ) ) );
328
329     m_urlList += url.prettyURL();
330
331     return TRUE;
332 }
333
334
335 /* delete cache */
336 /* when done, cacheDeleted SIGNAL emitted */ /* private */
337 bool ImgManager::deleteCachePrivate( const KURL& url, QWidget* parent )
338 {
339     if ( !cacheExists( url ) ) return FALSE;
340
341     if ( QMessageBox::warning( parent,
342                                "Kita",
343                                i18n( "Do you want to delete the image ?" ),
344                                QMessageBox::Ok, QMessageBox::Cancel | QMessageBox::Default )
345             == QMessageBox::Ok ) {
346
347         bool ret;;
348
349         QString path = Cache::getImgPath( url );
350         QString idxpath = Cache::getImgIdxPath( url );
351
352 #if KDE_IS_VERSION( 3, 2, 0 )
353         KIO::NetAccess::del( idxpath, m_mainwidget );
354         ret = KIO::NetAccess::del( path, m_mainwidget );
355 #else
356         KIO::NetAccess::del( idxpath );
357         ret = KIO::NetAccess::del( path );
358 #endif
359
360         if ( ret ) {
361             deleteImgDat( url );
362             emit cacheDeleted( url );
363         }
364
365         return ret;
366     }
367
368     return FALSE;
369 }
370
371
372 /* copy cache */ /* public */
373 bool ImgManager::copyCachePrivate( const KURL& url, QWidget* parent )
374 {
375     if ( !cacheExists( url ) ) return FALSE;
376
377     /* make filter */
378     QString filter;
379     QString file = url.fileName().lower();
380     int i = file.findRev( '.' );
381     if ( i == -1 ) filter = "*|All files";
382     else {
383         QString ext = file.mid( i );
384         filter = "*" + ext + "|*" + ext;
385     }
386
387     /* get filename */
388     QString savefile = KFileDialog::getSaveFileName( url.fileName(), filter, parent );
389     if ( savefile.isEmpty() ) return FALSE;
390
391     /* file exists */
392     if (
393 #if KDE_IS_VERSION( 3, 2, 0 )
394         KIO::NetAccess::exists( savefile, TRUE, m_mainwidget )
395 #else
396         KIO::NetAccess::exists( savefile )
397 #endif
398     ) {
399
400         if ( QMessageBox::warning( parent,
401                                    "Kita",
402                                    i18n( "Do you want to replace the file?" ),
403                                    QMessageBox::Ok, QMessageBox::Cancel | QMessageBox::Default )
404                 != QMessageBox::Ok ) return FALSE;
405
406 #if KDE_IS_VERSION( 3, 2, 0 )
407         KIO::NetAccess::del( savefile, m_mainwidget );
408 #else
409         KIO::NetAccess::del( savefile );
410 #endif
411
412     }
413
414     /* copy */
415     QString src = Cache::getImgPath( url );
416
417 #if KDE_IS_VERSION( 3, 2, 0 )
418     KIO::NetAccess::copy( src, savefile, m_mainwidget );
419 #else
420     KIO::NetAccess::copy( src, savefile );
421 #endif
422
423     return TRUE;
424 }
425
426
427 /* private */
428 void ImgManager::setMosaicPrivate( const KURL& url, bool status )
429 {
430     IMGDAT * imgdat = getImgDat( url );
431     if ( !imgdat ) return ;
432     if ( imgdat->code != 200 ) return ;
433
434     imgdat->mosaic = status;
435
436     /* save status */
437     KConfig cfg( Cache::getImgIdxPath( url ) );
438     cfg.writeEntry( "Mosaic", status );
439 }
440
441
442 /* private */
443 void ImgManager::createImgDat( const KURL& url, int code )
444 {
445     IMGDAT * imgdat = getImgDat( url );
446     if ( !imgdat ) {
447         imgdat = new IMGDAT;
448         m_imgDatDict.insert( url.prettyURL(), imgdat );
449     }
450
451     KConfig cfg( Cache::getImgIdxPath( url ) );
452     if ( code == 200 ) cfg.writeEntry( "URL", url.prettyURL() );
453
454     imgdat->mosaic = cfg.readBoolEntry( "Mosaic", KitaConfig::useMosaic() );
455     imgdat->height = cfg.readNumEntry( "Height", 0 );
456     imgdat->width = cfg.readNumEntry( "Width", 0 );
457     imgdat->size = cfg.readUnsignedNumEntry( "Size", 0 );
458     imgdat->datURL = cfg.readEntry( "datURL", QString::null );
459     imgdat->code = code;
460 }
461
462
463 /* private */
464 IMGDAT* ImgManager::getImgDat( const KURL& url )
465 {
466     return m_imgDatDict.find( url.prettyURL() );
467 }
468
469
470 /* private */
471 void ImgManager::deleteImgDat( const KURL& url )
472 {
473     IMGDAT * imgdat = getImgDat( url );
474     if ( !imgdat ) return ;
475
476     if ( m_imgDatDict.remove( url.prettyURL() ) ) {
477         delete imgdat;
478     }
479 }
480
481
482 /* private */
483 void ImgManager::getSize( const KURL& url )
484 {
485     IMGDAT * imgdat = getImgDat( url );
486     if ( !imgdat ) return ;
487     if ( imgdat->code != 200 ) return ;
488
489     QString path = Cache::getImgPath( url );
490     QImage img = QImage( path );
491
492     if ( !img.isNull() ) {
493
494         imgdat->width = img.width();
495         imgdat->height = img.height();
496
497         /* save size */
498         KConfig cfg( Cache::getImgIdxPath( url ) );
499         cfg.writeEntry( "Width", imgdat->width );
500         cfg.writeEntry( "Height", imgdat->height );
501     }
502 }
503
504
505 /* private */
506 bool ImgManager::cacheExists( const KURL& url )
507 {
508     if ( DownloadManager::isLoadingNow( url ) ) return FALSE;
509
510     bool ret;
511     QString path = Cache::getImgPath( url );
512
513 #if KDE_IS_VERSION( 3, 2, 0 )
514     ret = KIO::NetAccess::exists( path, TRUE, m_mainwidget );
515 #else
516     ret = KIO::NetAccess::exists( path );
517 #endif
518
519     if ( ret && !getImgDat( url ) ) createImgDat( url, 200 );
520
521     return ret;
522 }
523
524
525
526 /* This slot is called when loader received the data. */ /* private slot */
527 void ImgManager::slotData( const Kita::LoaderData& data, const QByteArray& barray )
528 {
529     /* check BMP header */
530     if ( barray.size() > 2 && data.size == barray.size()
531             && barray[ 0 ] == 'B' && barray[ 1 ] == 'M' ) {
532         DownloadManager::stopLoading( data.url );
533         return ;
534     }
535
536     /* I assume that file size is smaller than 2^32 byte */
537     emit receiveImgData( data.url, data.size, data.totalsize );
538 }
539
540
541 /* This slot is called when loading is done. */ /* private slot */
542 void ImgManager::slotResult( const Kita::LoaderData& data )
543 {
544     m_urlList.remove( data.url.prettyURL() );
545     createImgDat( data.url, data.code );
546
547     /* save size, datURL, etc */
548     if ( data.code == 200 ) {
549         unsigned int totalsize = data.totalsize;
550         KURL datURL = data.option.usrurl;
551         KConfig cfg( Cache::getImgIdxPath( data.url ) );
552         cfg.writeEntry( "Size", totalsize );
553         cfg.writeEntry( "datURL", datURL.prettyURL() );
554         IMGDAT* imgdat = instance->getImgDat( data.url );
555         imgdat->size = totalsize;
556         imgdat->datURL = datURL;
557     }
558
559     emit finishImgLoad( data.url );
560 }
561
562
563 /* protected */ /* virtual */
564 void ImgManager::customEvent( QCustomEvent * e )
565 {
566     /* emit finishImgLoad SIGNAL */
567     if ( e->type() == EVENT_EmitFinigh ) {
568         KURL url = static_cast< EmitFinishEvent* >( e ) ->url();
569         emit finishImgLoad( url );
570     }
571 }
572
573