]> git.lyx.org Git - features.git/blob - src/frontends/controllers/frontend_helpers.cpp
Move the lyx::biblio namespace into src/. Also make changes to how the BibTeX
[features.git] / src / frontends / controllers / frontend_helpers.cpp
1 /**
2  * \file frontend_helpers.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Angus Leeming
7  * \author Herbert Voß
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12 #include <config.h>
13
14 #include "frontend_helpers.h"
15
16 #include "Buffer.h"
17 #include "BufferParams.h"
18 #include "Color.h"
19 #include "debug.h"
20 #include "gettext.h"
21 #include "Language.h"
22 #include "Length.h"
23
24 #include "frontends/FileDialog.h"
25 #include "frontends/alert.h"
26
27 #include "support/filetools.h"
28 #include "support/lstrings.h"
29 #include "support/Package.h"
30 #include "support/filetools.h"
31 #include "support/lstrings.h"
32 #include "support/lyxalgo.h"
33 #include "support/os.h"
34 #include "support/Package.h"
35 #include "support/Path.h"
36 #include "support/Systemcall.h"
37
38 #include <boost/cregex.hpp>
39 #include <boost/regex.hpp>
40
41 #include <algorithm>
42 #include <fstream>
43
44 using std::string;
45 using std::vector;
46 using std::pair;
47 using std::endl;
48
49 namespace lyx {
50
51 namespace frontend {
52
53 vector<FamilyPair> const getFamilyData()
54 {
55         vector<FamilyPair> family(5);
56
57         FamilyPair pr;
58
59         pr.first = _("No change");
60         pr.second = Font::IGNORE_FAMILY;
61         family[0] = pr;
62
63         pr.first = _("Roman");
64         pr.second = Font::ROMAN_FAMILY;
65         family[1] = pr;
66
67         pr.first = _("Sans Serif");
68         pr.second = Font::SANS_FAMILY;
69         family[2] = pr;
70
71         pr.first = _("Typewriter");
72         pr.second = Font::TYPEWRITER_FAMILY;
73         family[3] = pr;
74
75         pr.first = _("Reset");
76         pr.second = Font::INHERIT_FAMILY;
77         family[4] = pr;
78
79         return family;
80 }
81
82
83 vector<SeriesPair> const getSeriesData()
84 {
85         vector<SeriesPair> series(4);
86
87         SeriesPair pr;
88
89         pr.first = _("No change");
90         pr.second = Font::IGNORE_SERIES;
91         series[0] = pr;
92
93         pr.first = _("Medium");
94         pr.second = Font::MEDIUM_SERIES;
95         series[1] = pr;
96
97         pr.first = _("Bold");
98         pr.second = Font::BOLD_SERIES;
99         series[2] = pr;
100
101         pr.first = _("Reset");
102         pr.second = Font::INHERIT_SERIES;
103         series[3] = pr;
104
105         return series;
106 }
107
108
109 vector<ShapePair> const getShapeData()
110 {
111         vector<ShapePair> shape(6);
112
113         ShapePair pr;
114
115         pr.first = _("No change");
116         pr.second = Font::IGNORE_SHAPE;
117         shape[0] = pr;
118
119         pr.first = _("Upright");
120         pr.second = Font::UP_SHAPE;
121         shape[1] = pr;
122
123         pr.first = _("Italic");
124         pr.second = Font::ITALIC_SHAPE;
125         shape[2] = pr;
126
127         pr.first = _("Slanted");
128         pr.second = Font::SLANTED_SHAPE;
129         shape[3] = pr;
130
131         pr.first = _("Small Caps");
132         pr.second = Font::SMALLCAPS_SHAPE;
133         shape[4] = pr;
134
135         pr.first = _("Reset");
136         pr.second = Font::INHERIT_SHAPE;
137         shape[5] = pr;
138
139         return shape;
140 }
141
142
143 vector<SizePair> const getSizeData()
144 {
145         vector<SizePair> size(14);
146
147         SizePair pr;
148
149         pr.first = _("No change");
150         pr.second = Font::IGNORE_SIZE;
151         size[0] = pr;
152
153         pr.first = _("Tiny");
154         pr.second = Font::SIZE_TINY;
155         size[1] = pr;
156
157         pr.first = _("Smallest");
158         pr.second = Font::SIZE_SCRIPT;
159         size[2] = pr;
160
161         pr.first = _("Smaller");
162         pr.second = Font::SIZE_FOOTNOTE;
163         size[3] = pr;
164
165         pr.first = _("Small");
166         pr.second = Font::SIZE_SMALL;
167         size[4] = pr;
168
169         pr.first = _("Normal");
170         pr.second = Font::SIZE_NORMAL;
171         size[5] = pr;
172
173         pr.first = _("Large");
174         pr.second = Font::SIZE_LARGE;
175         size[6] = pr;
176
177         pr.first = _("Larger");
178         pr.second = Font::SIZE_LARGER;
179         size[7] = pr;
180
181         pr.first = _("Largest");
182         pr.second = Font::SIZE_LARGEST;
183         size[8] = pr;
184
185         pr.first = _("Huge");
186         pr.second = Font::SIZE_HUGE;
187         size[9] = pr;
188
189         pr.first = _("Huger");
190         pr.second = Font::SIZE_HUGER;
191         size[10] = pr;
192
193         pr.first = _("Increase");
194         pr.second = Font::INCREASE_SIZE;
195         size[11] = pr;
196
197         pr.first = _("Decrease");
198         pr.second = Font::DECREASE_SIZE;
199         size[12] = pr;
200
201         pr.first = _("Reset");
202         pr.second = Font::INHERIT_SIZE;
203         size[13] = pr;
204
205         return size;
206 }
207
208
209 vector<BarPair> const getBarData()
210 {
211         vector<BarPair> bar(5);
212
213         BarPair pr;
214
215         pr.first = _("No change");
216         pr.second = IGNORE;
217         bar[0] = pr;
218
219         pr.first = _("Emph");
220         pr.second = EMPH_TOGGLE;
221         bar[1] = pr;
222
223         pr.first = _("Underbar");
224         pr.second = UNDERBAR_TOGGLE;
225         bar[2] = pr;
226
227         pr.first = _("Noun");
228         pr.second = NOUN_TOGGLE;
229         bar[3] = pr;
230
231         pr.first = _("Reset");
232         pr.second = INHERIT;
233         bar[4] = pr;
234
235         return bar;
236 }
237
238
239 vector<ColorPair> const getColorData()
240 {
241         vector<ColorPair> color(11);
242
243         ColorPair pr;
244
245         pr.first = _("No change");
246         pr.second = Color::ignore;
247         color[0] = pr;
248
249         pr.first = _("No color");
250         pr.second = Color::none;
251         color[1] = pr;
252
253         pr.first = _("Black");
254         pr.second = Color::black;
255         color[2] = pr;
256
257         pr.first = _("White");
258         pr.second = Color::white;
259         color[3] = pr;
260
261         pr.first = _("Red");
262         pr.second = Color::red;
263         color[4] = pr;
264
265         pr.first = _("Green");
266         pr.second = Color::green;
267         color[5] = pr;
268
269         pr.first = _("Blue");
270         pr.second = Color::blue;
271         color[6] = pr;
272
273         pr.first = _("Cyan");
274         pr.second = Color::cyan;
275         color[7] = pr;
276
277         pr.first = _("Magenta");
278         pr.second = Color::magenta;
279         color[8] = pr;
280
281         pr.first = _("Yellow");
282         pr.second = Color::yellow;
283         color[9] = pr;
284
285         pr.first = _("Reset");
286         pr.second = Color::inherit;
287         color[10] = pr;
288
289         return color;
290 }
291
292
293
294 namespace {
295
296 class Sorter
297         : public std::binary_function<LanguagePair,
298                                       LanguagePair, bool>
299 {
300 public:
301         bool operator()(LanguagePair const & lhs,
302                         LanguagePair const & rhs) const {
303                 return lhs.first < rhs.first;
304         }
305 };
306
307
308 class ColorSorter
309 {
310 public:
311         bool operator()(Color::color const & lhs,
312                         Color::color const & rhs) const {
313                 return lcolor.getGUIName(lhs) < lcolor.getGUIName(rhs);
314         }
315 };
316
317 } // namespace anon
318
319
320 vector<LanguagePair> const getLanguageData(bool character_dlg)
321 {
322         vector<LanguagePair>::size_type const size = character_dlg ?
323                 languages.size() + 2 : languages.size();
324
325         vector<LanguagePair> langs(size);
326
327         if (character_dlg) {
328                 langs[0].first = _("No change");
329                 langs[0].second = "ignore";
330                 langs[1].first = _("Reset");
331                 langs[1].second = "reset";
332         }
333
334         vector<string>::size_type i = character_dlg ? 2 : 0;
335         for (Languages::const_iterator cit = languages.begin();
336              cit != languages.end(); ++cit) {
337                 langs[i].first  = _(cit->second.display());
338                 langs[i].second = cit->second.lang();
339                 ++i;
340         }
341
342         // Don't sort "ignore" and "reset"
343         vector<LanguagePair>::iterator begin = character_dlg ?
344                 langs.begin() + 2 : langs.begin();
345
346         std::sort(begin, langs.end(), Sorter());
347
348         return langs;
349 }
350
351
352 vector<Color_color> const getSortedColors(vector<Color_color> colors)
353 {
354         // sort the colors
355         std::sort(colors.begin(), colors.end(), ColorSorter());
356         return colors;
357 }
358
359 } // namespace frontend
360
361 using support::addName;
362 using support::FileFilterList;
363 using support::getExtension;
364 using support::libFileSearch;
365 using support::makeAbsPath;
366 using support::makeRelPath;
367 using support::onlyFilename;
368 using support::onlyPath;
369 using support::package;
370 using support::prefixIs;
371 using support::removeExtension;
372
373 namespace frontend {
374
375
376 docstring const browseFile(docstring const & filename,
377                         docstring const & title,
378                         FileFilterList const & filters,
379                         bool save,
380                         pair<docstring,docstring> const & dir1,
381                         pair<docstring,docstring> const & dir2)
382 {
383         docstring lastPath = from_ascii(".");
384         if (!filename.empty())
385                 lastPath = from_utf8(onlyPath(to_utf8(filename)));
386
387         FileDialog fileDlg(title, LFUN_SELECT_FILE_SYNC, dir1, dir2);
388
389         FileDialog::Result result;
390
391         if (save)
392                 result = fileDlg.save(lastPath, filters,
393                                       from_utf8(onlyFilename(to_utf8(filename))));
394         else
395                 result = fileDlg.open(lastPath, filters,
396                                       from_utf8(onlyFilename(to_utf8(filename))));
397
398         return result.second;
399 }
400
401
402 docstring const browseRelFile(docstring const & filename,
403                            docstring const & refpath,
404                            docstring const & title,
405                            FileFilterList const & filters,
406                            bool save,
407                            pair<docstring,docstring> const & dir1,
408                            pair<docstring,docstring> const & dir2)
409 {
410         docstring const fname = from_utf8(makeAbsPath(
411                 to_utf8(filename), to_utf8(refpath)).absFilename());
412
413         docstring const outname = browseFile(fname, title, filters, save,
414                                           dir1, dir2);
415         docstring const reloutname = makeRelPath(outname, refpath);
416         if (prefixIs(reloutname, from_ascii("../")))
417                 return outname;
418         else
419                 return reloutname;
420 }
421
422
423
424 docstring const browseLibFile(docstring const & dir,
425                            docstring const & name,
426                            docstring const & ext,
427                            docstring const & title,
428                            FileFilterList const & filters)
429 {
430         // FIXME UNICODE
431         pair<docstring, docstring> const dir1(_("System files|#S#s"),
432                                        from_utf8(addName(package().system_support().absFilename(), to_utf8(dir))));
433
434         pair<docstring, docstring> const dir2(_("User files|#U#u"),
435                                        from_utf8(addName(package().user_support().absFilename(), to_utf8(dir))));
436
437         docstring const result = browseFile(from_utf8(
438                 libFileSearch(to_utf8(dir), to_utf8(name), to_utf8(ext)).absFilename()),
439                 title, filters, false, dir1, dir2);
440
441         // remove the extension if it is the default one
442         docstring noextresult;
443         if (from_utf8(getExtension(to_utf8(result))) == ext)
444                 noextresult = from_utf8(removeExtension(to_utf8(result)));
445         else
446                 noextresult = result;
447
448         // remove the directory, if it is the default one
449         docstring const file = from_utf8(onlyFilename(to_utf8(noextresult)));
450         if (from_utf8(libFileSearch(to_utf8(dir), to_utf8(file), to_utf8(ext)).absFilename()) == result)
451                 return file;
452         else
453                 return noextresult;
454 }
455
456
457 docstring const browseDir(docstring const & pathname,
458                        docstring const & title,
459                        pair<docstring,docstring> const & dir1,
460                        pair<docstring,docstring> const & dir2)
461 {
462         docstring lastPath = from_ascii(".");
463         if (!pathname.empty())
464                 lastPath = from_utf8(onlyPath(to_utf8(pathname)));
465
466         FileDialog fileDlg(title, LFUN_SELECT_FILE_SYNC, dir1, dir2);
467
468         FileDialog::Result const result =
469                 fileDlg.opendir(lastPath, from_utf8(onlyFilename(to_utf8(pathname))));
470
471         return result.second;
472 }
473
474
475 vector<docstring> const getLatexUnits()
476 {
477         vector<docstring> units;
478         int i = 0;
479         char const * str = stringFromUnit(i);
480         for (; str != 0; ++i, str = stringFromUnit(i))
481                 units.push_back(from_ascii(str));
482
483         return units;
484 }
485
486 } // namespace frontend
487
488
489 using support::bformat;
490 using support::contains;
491 using support::FileName;
492 using support::getExtension;
493 using support::getFileContents;
494 using support::getVectorFromString;
495 using support::libFileSearch;
496 using support::onlyFilename;
497 using support::package;
498 using support::quoteName;
499 using support::split;
500 using support::Systemcall;
501 using support::token;
502
503 namespace frontend {
504
505 void rescanTexStyles()
506 {
507         // Run rescan in user lyx directory
508         support::Path p(package().user_support());
509         FileName const command = libFileSearch("scripts", "TeXFiles.py");
510         Systemcall one;
511         int const status = one.startscript(Systemcall::Wait,
512                         lyx::support::os::python() + ' ' +
513                         quoteName(command.toFilesystemEncoding()));
514         if (status == 0)
515                 return;
516         // FIXME UNICODE
517         Alert::error(_("Could not update TeX information"),
518                      bformat(_("The script `%s' failed."), lyx::from_utf8(command.absFilename())));
519 }
520
521
522 void texhash()
523 {
524         // Run texhash in user lyx directory
525         support::Path p(package().user_support());
526
527         //path to texhash through system
528         Systemcall one;
529         one.startscript(Systemcall::Wait,"texhash");
530 }
531
532
533 void getTexFileList(string const & filename, std::vector<string> & list)
534 {
535         list.clear();
536         FileName const file = libFileSearch("", filename);
537         if (file.empty())
538                 return;
539
540         list = getVectorFromString(getFileContents(file), "\n");
541
542         // Normalise paths like /foo//bar ==> /foo/bar
543         boost::RegEx regex("/{2,}");
544         std::vector<string>::iterator it  = list.begin();
545         std::vector<string>::iterator end = list.end();
546         for (; it != end; ++it) {
547                 *it = regex.Merge((*it), "/");
548         }
549
550         // remove empty items and duplicates
551         list.erase(std::remove(list.begin(), list.end(), ""), list.end());
552         eliminate_duplicates(list);
553 }
554
555
556 string const getListOfOptions(string const & classname, string const & type)
557 {
558         FileName const filename(getTexFileFromList(classname, type));
559         if (filename.empty())
560                 return string();
561         string optionList = string();
562         std::ifstream is(filename.toFilesystemEncoding().c_str());
563         while (is) {
564                 string s;
565                 is >> s;
566                 if (contains(s,"DeclareOption")) {
567                         s = s.substr(s.find("DeclareOption"));
568                         s = split(s,'{');               // cut front
569                         s = token(s,'}',0);             // cut end
570                         optionList += (s + '\n');
571                 }
572         }
573         return optionList;
574 }
575
576
577 string const getTexFileFromList(string const & file,
578                             string const & type)
579 {
580         string file_ = file;
581         // do we need to add the suffix?
582         if (!(getExtension(file) == type))
583                 file_ += '.' + type;
584
585         lyxerr << "Searching for file " << file_ << endl;
586
587         string lstfile;
588         if (type == "cls")
589                 lstfile = "clsFiles.lst";
590         else if (type == "sty")
591                 lstfile = "styFiles.lst";
592         else if (type == "bst")
593                 lstfile = "bstFiles.lst";
594         else if (type == "bib")
595                 lstfile = "bibFiles.lst";
596         FileName const abslstfile = libFileSearch(string(), lstfile);
597         if (abslstfile.empty()) {
598                 lyxerr << "File `'" << lstfile << "' not found." << endl;
599                 return string();
600         }
601         string const allClasses = getFileContents(abslstfile);
602         int entries = 0;
603         string classfile = token(allClasses, '\n', entries);
604         int count = 0;
605         while ((!contains(classfile, file) ||
606                 (onlyFilename(classfile) != file)) &&
607                 (++count < 1000)) {
608                 classfile = token(allClasses, '\n', ++entries);
609         }
610
611         // now we have filename with full path
612         lyxerr << "with full path: " << classfile << endl;
613
614         return classfile;
615 }
616
617 } // namespace frontend
618 } // namespace lyx