1 /***************************************************************************
2     Copyright (C) 2003-2009 Robby Stephenson <robby@periapsis.org>
3  ***************************************************************************/
4 
5 /***************************************************************************
6  *                                                                         *
7  *   This program is free software; you can redistribute it and/or         *
8  *   modify it under the terms of the GNU General Public License as        *
9  *   published by the Free Software Foundation; either version 2 of        *
10  *   the License or (at your option) version 3 or any later version        *
11  *   accepted by the membership of KDE e.V. (or its successor approved     *
12  *   by the membership of KDE e.V.), which shall act as a proxy            *
13  *   defined in Section 14 of version 3 of the license.                    *
14  *                                                                         *
15  *   This program is distributed in the hope that it will be useful,       *
16  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
17  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
18  *   GNU General Public License for more details.                          *
19  *                                                                         *
20  *   You should have received a copy of the GNU General Public License     *
21  *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
22  *                                                                         *
23  ***************************************************************************/
24 
25 #ifndef TELLICO_IMAGEFACTORY_H
26 #define TELLICO_IMAGEFACTORY_H
27 
28 #include "../utils/stringset.h"
29 
30 #include <QUrl>
31 #include <QObject>
32 #include <QColor>
33 #include <QHash>
34 #include <QPixmap>
35 
36 #include <memory>
37 
38 class KZip;
39 class KJob;
40 
41 namespace Tellico {
42   namespace Data {
43     class Image;
44     class ImageInfo;
45   }
46   class ImageDirectory;
47 
48 class StyleOptions {
49 public:
50   QString fontFamily;
51   int fontSize;
52   QColor baseColor;
53   QColor textColor;
54   QColor highlightedBaseColor;
55   QColor highlightedTextColor;
56   QString imgDir;
57 };
58 
59 /**
60  * @author Robby Stephenson
61  */
62 class ImageFactory : public QObject {
63 Q_OBJECT
64 
65 public:
66   enum CacheDir {
67     TempDir,
68     DataDir,
69     LocalDir,
70     ZipArchive
71   };
72 
73   /**
74    * setup some of the static members
75    */
76   static void init();
77 
78   /**
79    * Returns the temporary directory where image files are saved
80    *
81    * @return The full path
82    */
83   static QString tempDir();
84   static QString dataDir();
85   static QString localDir();
86   static QString imageDir();
87   static CacheDir cacheDir();
88 
89   /**
90    * Add an image, reading it from a URL, which is the case when adding a new image from the
91    * @ref ImageWidget.
92    *
93    * @param url The URL of the image, anything KIO can handle
94    * @param quiet If any error should not be reported.
95    * @return The image id, empty if null
96    */
97   static QString addImage(const QUrl& url, bool quiet=false,
98                           const QUrl& referrer = QUrl(), bool linkOnly=false);
99   /**
100    * Add an image, reading it from a regular QImage, which is the case when dragging and dropping
101    * an image in the @ref ImageWidget. The format has to be included, since the QImage doesn't
102    * 'know' what format it came from.
103    *
104    * @param image The qimage
105    * @param format The image format, probably "PNG"
106    * @return The image id, empty if null
107    */
108   static QString addImage(const QImage& image, const QString& format);
109   static QString addImage(const QPixmap& image, const QString& format);
110   /**
111    * Add an image, reading it from data, which is the case when reading from the data file, and
112    * using the @p format and @p id as the image id. The image id is checked in the image cache
113    * image dict first, and then if it is not found, a new Image is constructed. The new image is
114    * inserted in the dict, and the image info is cached.
115    *
116    * @param data The image data
117    * @param format The image format, from Qt's output format list
118    * @param id The internal id of the image
119    * @return The image id, empty if null
120    */
121   static QString addImage(const QByteArray& data, const QString& format, const QString& id);
122 
123   static bool writeCachedImage(const QString& id, CacheDir dir, bool force = false);
124   static bool writeCachedImage(const QString& id, ImageDirectory* dir, bool force = false);
125 
126   /**
127    * Returns an image reference given its id. If none is found, a null image
128    * is returned.
129    *
130    * @param id The image id
131    * @return The image reference
132    */
133   static const Data::Image& imageById(const QString& id);
134   static bool hasLocalImage(const QString& id);
135   bool hasImageInMemory(const QString& id) const;
136   // just used for testing
137   bool hasNullImage(const QString& id) const;
138   /**
139    * Requests an image to be made available. Images already in the cache or available locally are
140    * considered to be instantly available. Otherwise, the id is assumed to be a URL and is downloaded
141    * The imageAvailable() signal is used to indicate completion and availability of the image.
142    *
143    * @param id The image id
144    */
145   static void requestImageById(const QString& id);
146   static Data::ImageInfo imageInfo(const QString& id);
147   static void cacheImageInfo(const Data::ImageInfo& info);
148   static bool hasImageInfo(const QString& id);
149   // basically returns !imageById().isNull()
150   static bool validImage(const QString& id);
151 
152   static QPixmap pixmap(const QString& id, int w, int h);
153 
154   /**
155    * Clear the image cache and dict
156    * if deleteTempDirectory = true, then clean the temp dir and remove all temporary image files
157    */
158   static void clean(bool deleteTempDirectory);
159   /**
160    * Creates the gradient images used in the entry view.
161    */
162   static void createStyleImages(int collectionType, const StyleOptions& options = StyleOptions());
163 
164   static void removeImage(const QString& id_, bool deleteImage);
165   static StringSet imagesNotInCache();
166 
167   static QString localDirectory(const QUrl& url);
168   static void setLocalDirectory(const QUrl& url);
169   static void setZipArchive(std::unique_ptr<KZip> zip);
170 
171   static ImageFactory* self();
172 
173 Q_SIGNALS:
174   void imageAvailable(const QString& id);
175   void imageLocationMismatch();
176 
177 private Q_SLOTS:
178   void slotImageJobResult(KJob* job);
179 
180 private:
181   /**
182    * Add an image, reading it from a URL, which is the case when adding a new image from the
183    * @ref ImageWidget.
184    *
185    * @param url The URL of the image, anything KIO can handle
186    * @param quiet If any error should not be reported.
187    * @return The image
188    */
189   const Data::Image& addImageImpl(const QUrl& url, bool quiet=false,
190                                   const QUrl& referrer = QUrl(), bool linkOnly = false);
191   void requestImageByUrlImpl(const QUrl& url, bool quiet=false,
192                              const QUrl& referrer = QUrl(), bool linkOnly = false);
193   /**
194    * Add an image, reading it from a regular QImage, which is the case when dragging and dropping
195    * an image in the @ref ImageWidget. The format has to be included, since the QImage doesn't
196    * 'know' what format it came from.
197    *
198    * @param image The qimage
199    * @param format The image format, probably "PNG"
200    * @return The image
201    */
202   const Data::Image& addImageImpl(const QImage& image, const QString& format);
203   /**
204    * Add an image, reading it from data, which is the case when reading from the data file. The
205    * @p id isn't strictly needed, since it can be reconstructed from the image data and format, but
206    * since it's already known, go ahead and use it.
207    *
208    * @param data The image data
209    * @param format The image format, from Qt's output format list
210    * @param id The internal id of the image
211    * @return The image
212    */
213   const Data::Image& addImageImpl(const QByteArray& data, const QString& format, const QString& id);
214 
215   const Data::Image& addCachedImageImpl(const QString& id, CacheDir dir);
216 
217   static ImageFactory* factory;
218 
219   static QHash<QString, Data::ImageInfo> s_imageInfoMap;
220   static StringSet s_imagesToRelease;
221 
222   ImageFactory();
223   ~ImageFactory();
224 
225   void releaseImages();
226   void emitImageMismatch();
227 
228   class Private;
229   Private* const d;
230 };
231 
232 } // end namespace
233 
234 #endif
235