]> git.lyx.org Git - lyx.git/blob - src/exporter.C
Enable LyX to start up under Cygwin.
[lyx.git] / src / exporter.C
1 /**
2  * \file exporter.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author unknown
7  * \author Alfredo Braunstein
8  * \author Lars Gullik Bjønnes
9  * \author Jean Marc Lasgouttes
10  * \author Angus Leeming
11  * \author John Levon
12  * \author André Pönitz
13  *
14  * Full author contact details are available in file CREDITS.
15  */
16
17 #include <config.h>
18
19 #include "exporter.h"
20
21 #include "buffer.h"
22 #include "buffer_funcs.h"
23 #include "bufferparams.h"
24 #include "converter.h"
25 #include "format.h"
26 #include "gettext.h"
27 #include "lyxrc.h"
28 #include "mover.h"
29 #include "output_plaintext.h"
30 #include "outputparams.h"
31 #include "frontends/Alert.h"
32
33 #include "support/FileInfo.h"
34 #include "support/filetools.h"
35 #include "support/lyxlib.h"
36 #include "support/os.h"
37
38 using lyx::support::AddName;
39 using lyx::support::bformat;
40 using lyx::support::ChangeExtension;
41 using lyx::support::contains;
42 using lyx::support::MakeAbsPath;
43 using lyx::support::MakeDisplayPath;
44 using lyx::support::OnlyFilename;
45 using lyx::support::OnlyPath;
46 using lyx::support::prefixIs;
47
48 using std::find;
49 using std::string;
50 using std::vector;
51
52
53 namespace {
54
55 vector<string> const Backends(Buffer const & buffer)
56 {
57         vector<string> v;
58         if (buffer.params().getLyXTextClass().isTeXClassAvailable())
59                 v.push_back(BufferFormat(buffer));
60         v.push_back("text");
61         return v;
62 }
63
64
65 /// ask the user what to do if a file already exists
66 int checkOverwrite(string const & filename)
67 {
68         if (lyx::support::FileInfo(filename, true).exist()) {
69                 string text = bformat(_("The file %1$s already exists.\n\n"
70                                         "Do you want to over-write that file?"),
71                                       MakeDisplayPath(filename));
72                 return Alert::prompt(_("Over-write file?"),
73                                      text, 0, 2,
74                                      _("&Over-write"), _("Over-write &all"),
75                                      _("&Cancel export"));
76         }
77         return 0;
78 }
79
80
81 enum CopyStatus {
82         SUCCESS,
83         FORCE,
84         CANCEL
85 };
86
87
88 /** copy file \p sourceFile to \p destFile. If \p force is false, the user
89  *  will be asked before existing files are overwritten.
90  *  \return
91  *  - SUCCESS if this file got copied
92  *  - FORCE   if subsequent calls should not ask for confirmation before
93  *            overwriting files anymore.
94  *  - CANCEL  if the export should be cancelled
95  */
96 CopyStatus copyFile(string const & format,
97                     string const & sourceFile, string const & destFile,
98                     string const & latexFile, bool force)
99 {
100         CopyStatus ret = force ? FORCE : SUCCESS;
101
102         // Only copy files that are in our tmp dir, all other files would
103         // overwrite themselves. This check could be changed to
104         // boost::filesystem::equivalent(sourceFile, destFile) if export to
105         // other directories than the document directory is desired.
106         if (!prefixIs(OnlyPath(sourceFile), lyx::support::os::getTmpDir()))
107                 return ret;
108
109         if (!force) {
110                 switch(checkOverwrite(destFile)) {
111                 case 0:
112                         ret = SUCCESS;
113                         break;
114                 case 1:
115                         ret = FORCE;
116                         break;
117                 default:
118                         return CANCEL;
119                 }
120         }
121
122         Mover const & mover = movers(format);
123         if (!mover.copy(sourceFile, destFile, latexFile))
124                 Alert::error(_("Couldn't copy file"),
125                              bformat(_("Copying %1$s to %2$s failed."),
126                                      MakeDisplayPath(sourceFile),
127                                      MakeDisplayPath(destFile)));
128
129         return ret;
130 }
131
132 } //namespace anon
133
134
135 bool Exporter::Export(Buffer * buffer, string const & format,
136                       bool put_in_tempdir, string & result_file)
137 {
138         string backend_format;
139         OutputParams runparams;
140         runparams.flavor = OutputParams::LATEX;
141         runparams.linelen = lyxrc.ascii_linelen;
142         vector<string> backends = Backends(*buffer);
143         if (find(backends.begin(), backends.end(), format) == backends.end()) {
144                 for (vector<string>::const_iterator it = backends.begin();
145                      it != backends.end(); ++it) {
146                         Graph::EdgePath p =
147                                 converters.getPath(*it, format);
148                         if (!p.empty()) {
149                                 runparams.flavor = converters.getFlavor(p);
150                                 backend_format = *it;
151                                 break;
152                         }
153                 }
154                 if (backend_format.empty()) {
155                         Alert::error(_("Couldn't export file"),
156                                 bformat(_("No information for exporting the format %1$s."),
157                                    formats.prettyName(format)));
158                         return false;
159                 }
160         } else
161                 backend_format = format;
162
163         string filename = buffer->getLatexName(false);
164         filename = AddName(buffer->temppath(), filename);
165         filename = ChangeExtension(filename,
166                                    formats.extension(backend_format));
167
168         // Ascii backend
169         if (backend_format == "text")
170                 writeFileAscii(*buffer, filename, runparams);
171         // Linuxdoc backend
172         else if (buffer->isLinuxDoc()) {
173                 runparams.nice = !put_in_tempdir;
174                 buffer->makeLinuxDocFile(filename, runparams);
175         }
176         // Docbook backend
177         else if (buffer->isDocBook()) {
178                 runparams.nice = !put_in_tempdir;
179                 buffer->makeDocBookFile(filename, runparams);
180         }
181         // LaTeX backend
182         else if (backend_format == format) {
183                 runparams.nice = true;
184                 buffer->makeLaTeXFile(filename, string(), runparams);
185         } else if (contains(buffer->filePath(), ' ')) {
186                 Alert::error(_("File name error"),
187                            _("The directory path to the document cannot contain spaces."));
188                 return false;
189         } else {
190                 runparams.nice = false;
191                 buffer->makeLaTeXFile(filename, buffer->filePath(), runparams);
192         }
193
194         if (!converters.convert(buffer, filename, filename,
195                                 backend_format, format, result_file))
196                 return false;
197
198         if (!put_in_tempdir) {
199                 string const tmp_result_file = result_file;
200                 result_file = ChangeExtension(buffer->fileName(),
201                                               formats.extension(format));
202                 // We need to copy referenced files (e. g. included graphics
203                 // if format == "dvi") to the result dir.
204                 vector<ExportedFile> const files =
205                         runparams.exportdata->externalFiles(format);
206                 string const dest = OnlyPath(result_file);
207                 CopyStatus status = SUCCESS;
208                 for (vector<ExportedFile>::const_iterator it = files.begin();
209                                 it != files.end() && status != CANCEL; ++it) {
210                         string const fmt =
211                                 formats.getFormatFromFile(it->sourceName);
212                         status = copyFile(fmt, it->sourceName,
213                                           MakeAbsPath(it->exportName, dest),
214                                           it->exportName, status == FORCE);
215                 }
216                 if (status == CANCEL) {
217                         buffer->message(_("Document export cancelled."));
218                 } else {
219                         // Finally copy the main file
220                         status = copyFile(format, tmp_result_file,
221                                           result_file, result_file,
222                                           status == FORCE);
223                         buffer->message(bformat(_("Document exported as %1$s"
224                                                   "to file `%2$s'"),
225                                                 formats.prettyName(format),
226                                                 MakeDisplayPath(result_file)));
227                 }
228         }
229
230         return true;
231 }
232
233
234 bool Exporter::Export(Buffer * buffer, string const & format,
235                       bool put_in_tempdir)
236 {
237         string result_file;
238         return Export(buffer, format, put_in_tempdir, result_file);
239 }
240
241
242 bool Exporter::Preview(Buffer * buffer, string const & format)
243 {
244         string result_file;
245         if (!Export(buffer, format, true, result_file))
246                 return false;
247         return formats.view(*buffer, result_file, format);
248 }
249
250
251 bool Exporter::IsExportable(Buffer const & buffer, string const & format)
252 {
253         vector<string> backends = Backends(buffer);
254         for (vector<string>::const_iterator it = backends.begin();
255              it != backends.end(); ++it)
256                 if (converters.isReachable(*it, format))
257                         return true;
258         return false;
259 }
260
261
262 vector<Format const *> const
263 Exporter::GetExportableFormats(Buffer const & buffer, bool only_viewable)
264 {
265         vector<string> backends = Backends(buffer);
266         vector<Format const *> result =
267                 converters.getReachable(backends[0], only_viewable, true);
268         for (vector<string>::const_iterator it = backends.begin() + 1;
269              it != backends.end(); ++it) {
270                 vector<Format const *>  r =
271                         converters.getReachable(*it, only_viewable, false);
272                 result.insert(result.end(), r.begin(), r.end());
273         }
274         return result;
275 }
276
277
278 ExportedFile::ExportedFile(string const & s, string const & e) :
279         sourceName(s), exportName(e) {}
280
281
282 bool operator==(ExportedFile const & f1, ExportedFile const & f2)
283 {
284         return f1.sourceName == f2.sourceName &&
285                f1.exportName == f2.exportName;
286
287 }
288
289
290 void ExportData::addExternalFile(string const & format,
291                                  string const & sourceName,
292                                  string const & exportName)
293 {
294         BOOST_ASSERT(lyx::support::AbsolutePath(sourceName));
295
296         // Make sure that we have every file only once, otherwise copyFile()
297         // would ask several times if it should overwrite a file.
298         vector<ExportedFile> & files = externalfiles[format];
299         ExportedFile file(sourceName, exportName);
300         if (find(files.begin(), files.end(), file) == files.end())
301                 files.push_back(file);
302 }
303
304
305 void ExportData::addExternalFile(string const & format,
306                                  string const & sourceName)
307 {
308         addExternalFile(format, sourceName, OnlyFilename(sourceName));
309 }
310
311
312 vector<ExportedFile> const
313 ExportData::externalFiles(string const & format) const
314 {
315         FileMap::const_iterator cit = externalfiles.find(format);
316         if (cit != externalfiles.end())
317                 return cit->second;
318         return vector<ExportedFile>();
319 }