]> git.lyx.org Git - lyx.git/blob - src/graphics/GraphicsCacheItem.C
* Split the graphics loader into a frontend and a backend.
[lyx.git] / src / graphics / GraphicsCacheItem.C
1 /*
2  * \file GraphicsCacheItem.C
3  * Copyright 2002 the LyX Team
4  * Read the file COPYING
5  *
6  * \author Baruch Even <baruch.even@writeme.com>
7  * \author Herbert Voss <voss@lyx.org>
8  * \author Angus Leeming <a.leeming@ic.ac.uk>
9  */
10
11 #include <config.h>
12
13 #ifdef __GNUG__
14 #pragma implementation
15 #endif
16
17 #include "graphics/GraphicsCacheItem.h"
18 #include "graphics/GraphicsImage.h"
19 #include "graphics/GraphicsConverter.h"
20
21 #include "debug.h"
22
23 #include "support/LAssert.h"
24 #include "support/filetools.h"
25
26 #include <boost/bind.hpp>
27
28 using std::endl;
29
30
31 namespace grfx {
32
33 GCacheItem::GCacheItem(string const & file)
34         : filename_(file), zipped_(false),
35           remove_loaded_file_(false), status_(WaitingToLoad)
36 {}
37
38
39 void GCacheItem::startLoading()
40 {
41         if (status() != WaitingToLoad)
42                 return;
43
44         convertToDisplayFormat();
45 }
46
47
48 void GCacheItem::setStatus(ImageStatus new_status)
49 {
50         if (status_ == new_status)
51                 return;
52
53         status_ = new_status;
54         statusChanged();
55 }
56
57
58 void GCacheItem::imageConverted(string const & file_to_load)
59 {
60         bool const success =
61                 (!file_to_load.empty() && IsFileReadable(file_to_load));
62
63         string const text = success ? "succeeded" : "failed";
64         lyxerr[Debug::GRAPHICS] << "Image conversion " << text << "." << endl;
65
66         if (!success) {
67                 setStatus(ErrorConverting);
68
69                 if (zipped_)
70                         lyx::unlink(unzipped_filename_);
71
72                 return;
73         }
74
75         cc_.disconnect();
76
77         // Do the actual image loading from file to memory.
78         file_to_load_ = file_to_load;
79
80         loadImage();
81 }
82
83
84 // This function gets called from the callback after the image has been
85 // converted successfully.
86 void GCacheItem::loadImage()
87 {
88         setStatus(Loading);
89         lyxerr[Debug::GRAPHICS] << "Loading image." << endl;
90
91         // Connect a signal to this->imageLoaded and pass this signal to
92         // GImage::loadImage.
93         SignalLoadTypePtr on_finish;
94         on_finish.reset(new SignalLoadType);
95         cl_ = on_finish->connect(boost::bind(&GCacheItem::imageLoaded, this, _1));
96
97         image_ = GImage::newImage();
98         image_->load(file_to_load_, on_finish);
99 }
100
101
102 void GCacheItem::imageLoaded(bool success)
103 {
104         string const text = success ? "succeeded" : "failed";
105         lyxerr[Debug::GRAPHICS] << "Image loading " << text << "." << endl;
106
107         // Clean up after loading.
108         if (zipped_)
109                 lyx::unlink(unzipped_filename_);
110
111         if (remove_loaded_file_ && unzipped_filename_ != file_to_load_)
112                 lyx::unlink(file_to_load_);
113
114         cl_.disconnect();
115
116         if (!success) {
117                 setStatus(ErrorLoading);
118                 return;
119         }
120
121         setStatus(Loaded);
122 }
123
124
125 namespace {
126
127 string const findTargetFormat(string const & from)
128 {
129         typedef GImage::FormatList FormatList;
130         FormatList const formats = GImage::loadableFormats();
131
132         // There must be a format to load from.
133         lyx::Assert(!formats.empty());
134
135         // First ascertain if we can load directly with no conversion
136         FormatList::const_iterator it1  = formats.begin();
137         FormatList::const_iterator end = formats.end();
138         for (; it1 != end; ++it1) {
139                 if (from == *it1)
140                         return *it1;
141         }
142
143         // So, we have to convert to a loadable format. Can we?
144         grfx::GConverter const & graphics_converter = grfx::GConverter::get();
145
146         FormatList::const_iterator it2  = formats.begin();
147         for (; it2 != end; ++it2) {
148                 if (graphics_converter.isReachable(from, *it2))
149                         return *it2;
150         }
151
152         // Failed! so we have to try to convert it to XPM format
153         // with the standard converter
154         return string("xpm");
155 }
156
157 } // anon namespace
158
159
160 void GCacheItem::convertToDisplayFormat()
161 {
162         setStatus(Converting);
163         // Make a local copy in case we unzip it
164         string const filename = zippedFile(filename_) ?
165                 unzipFile(filename_) : filename_; 
166         string const displayed_filename = MakeDisplayPath(filename_);
167         lyxerr[Debug::GRAPHICS] << "[GrahicsCacheItem::convertToDisplayFormat]\n"
168                 << "\tAttempting to convert image file: " << filename
169                 << "\n\twith displayed filename: " << displayed_filename
170                 << endl;
171
172         // First, check that the file exists!
173         if (!IsFileReadable(filename)) {
174                 setStatus(ErrorNoFile);
175                 lyxerr[Debug::GRAPHICS] << "\tThe file is not readable" << endl;
176                 return;
177         }
178
179         string from = getExtFromContents(filename);
180         // Some old ps-files make problems, so we do not need direct
181         // loading of an ps-file
182         if (from == "ps") {
183                 lyxerr[Debug::GRAPHICS] 
184                 << "\n\tThe file contains PostScript format data.\n" 
185                 << "\tchanging it to eps-format to get it converted to xpm\n";
186                 from = "eps";
187         } else
188                 lyxerr[Debug::GRAPHICS] 
189                         << "\n\tThe file contains " << from << " format data." << endl;
190         string const to = grfx::findTargetFormat(from);
191
192         if (from == to) {
193                 // No conversion needed!
194                 lyxerr[Debug::GRAPHICS] << "\tNo conversion needed (from == to)!" << endl;
195                 file_to_load_ = filename;
196                 loadImage();
197                 return;
198         }
199
200         lyxerr[Debug::GRAPHICS] << "\tConverting it to " << to << " format." << endl;
201         // Take only the filename part of the file, without path or extension.
202         string const temp = ChangeExtension(OnlyFilename(filename), string());
203
204         // Add some stuff to create a uniquely named temporary file.
205         // This file is deleted in loadImage after it is loaded into memory.
206         string const to_file_base = lyx::tempName(string(), temp);
207         remove_loaded_file_ = true;
208
209         // Remove the temp file, we only want the name...
210         lyx::unlink(to_file_base);
211
212         // Connect a signal to this->imageConverted and pass this signal to
213         // the graphics converter so that we can load the modified file
214         // on completion of the conversion process.
215         SignalConvertTypePtr on_finish;
216         on_finish.reset(new SignalConvertType);
217         cc_ = on_finish->connect(boost::bind(&GCacheItem::imageConverted, this, _1));
218
219         GConverter & graphics_converter = GConverter::get();
220         graphics_converter.convert(filename, to_file_base, from, to, on_finish);
221 }
222
223 } // namespace grfx