]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/qt_helpers.cpp
Remove unused variables
[lyx.git] / src / frontends / qt4 / qt_helpers.cpp
1 /**
2  * \file qt_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 Dekel Tsur
7  * \author Jürgen Spitzmüller
8  * \author Richard Heck
9  *
10  * Full author contact details are available in file CREDITS.
11  */
12
13 #include <config.h>
14
15 #include "qt_helpers.h"
16
17 #include "FileDialog.h"
18 #include "LengthCombo.h"
19
20 #include "frontends/alert.h"
21
22 #include "BufferParams.h"
23 #include "FloatList.h"
24 #include "IndicesList.h"
25 #include "Language.h"
26 #include "Length.h"
27 #include "TextClass.h"
28
29 #include "support/convert.h"
30 #include "support/debug.h"
31 #include "support/foreach.h"
32 #include "support/gettext.h"
33 #include "support/lstrings.h"
34 #include "support/lyxalgo.h"
35 #include "support/os.h"
36 #include "support/Package.h"
37 #include "support/PathChanger.h"
38 #include "support/Systemcall.h"
39
40 #include <QCheckBox>
41 #include <QComboBox>
42 #include <QLineEdit>
43 #include <QLocale>
44 #include <QPalette>
45 #include <QSet>
46
47 #include <algorithm>
48 #include <fstream>
49 #include <locale>
50
51 // for FileFilter.
52 // FIXME: Remove
53 #include "support/regex.h"
54 #include <boost/tokenizer.hpp>
55
56
57 using namespace std;
58 using namespace lyx::support;
59
60 namespace lyx {
61
62 FileName libFileSearch(QString const & dir, QString const & name,
63                                 QString const & ext, search_mode mode)
64 {
65         return support::libFileSearch(fromqstr(dir), fromqstr(name), fromqstr(ext), mode);
66 }
67
68
69 FileName imageLibFileSearch(QString & dir, QString const & name,
70                                 QString const & ext, search_mode mode)
71 {
72         string tmp = fromqstr(dir);
73         FileName fn = support::imageLibFileSearch(tmp, fromqstr(name), fromqstr(ext), mode);
74         dir = toqstr(tmp);
75         return fn;
76 }
77
78 namespace {
79
80 double locstringToDouble(QString const & str)
81 {
82         QLocale loc;
83         bool ok;
84         double res = loc.toDouble(str, &ok);
85         if (!ok) {
86                 // Fall back to C
87                 QLocale c(QLocale::C);
88                 res = c.toDouble(str);
89         }
90         return res;
91 }
92
93 } // namespace anon
94
95
96 namespace frontend {
97
98 string widgetsToLength(QLineEdit const * input, LengthCombo const * combo)
99 {
100         QString const length = input->text();
101         if (length.isEmpty())
102                 return string();
103
104         // Don't return unit-from-choice if the input(field) contains a unit
105         if (isValidGlueLength(fromqstr(length)))
106                 return fromqstr(length);
107
108         Length::UNIT const unit = combo->currentLengthItem();
109
110         return Length(locstringToDouble(length.trimmed()), unit).asString();
111 }
112
113
114 Length widgetsToLength(QLineEdit const * input, QComboBox const * combo)
115 {
116         QString const length = input->text();
117         if (length.isEmpty())
118                 return Length();
119
120         // don't return unit-from-choice if the input(field) contains a unit
121         if (isValidGlueLength(fromqstr(length)))
122                 return Length(fromqstr(length));
123
124         Length::UNIT unit = Length::UNIT_NONE;
125         QString const item = combo->currentText();
126         for (int i = 0; i < num_units; i++) {
127                 if (qt_(lyx::unit_name_gui[i]) == item) {
128                         unit = unitFromString(unit_name[i]);
129                         break;
130                 }
131         }
132
133         return Length(locstringToDouble(length.trimmed()), unit);
134 }
135
136
137 void lengthToWidgets(QLineEdit * input, LengthCombo * combo,
138         Length const & len, Length::UNIT /*defaultUnit*/)
139 {
140         if (len.empty()) {
141                 // no length (UNIT_NONE)
142                 combo->setCurrentItem(Length::defaultUnit());
143                 input->setText("");
144         } else {
145                 combo->setCurrentItem(len.unit());
146                 QLocale loc;
147                 loc.setNumberOptions(QLocale::OmitGroupSeparator);
148                 input->setText(formatLocFPNumber(Length(len).value()));
149         }
150 }
151
152
153 void lengthToWidgets(QLineEdit * input, LengthCombo * combo,
154         string const & len, Length::UNIT defaultUnit)
155 {
156         if (len.empty()) {
157                 // no length (UNIT_NONE)
158                 combo->setCurrentItem(defaultUnit);
159                 input->setText("");
160         } else if (!isValidLength(len) && !isStrDbl(len)) {
161                 // use input field only for gluelengths
162                 combo->setCurrentItem(defaultUnit);
163                 input->setText(toqstr(len));
164         } else {
165                 lengthToWidgets(input, combo, Length(len), defaultUnit);
166         }
167 }
168
169
170 void lengthToWidgets(QLineEdit * input, LengthCombo * combo,
171         docstring const & len, Length::UNIT defaultUnit)
172 {
173         lengthToWidgets(input, combo, to_utf8(len), defaultUnit);
174 }
175
176
177 double widgetToDouble(QLineEdit const * input)
178 {
179         QString const text = input->text();
180         if (text.isEmpty())
181                 return 0.0;
182
183         return locstringToDouble(text.trimmed());
184 }
185
186
187 string widgetToDoubleStr(QLineEdit const * input)
188 {
189         return convert<string>(widgetToDouble(input));
190 }
191
192
193 void doubleToWidget(QLineEdit * input, double const & value, char f, int prec)
194 {
195         QLocale loc;
196         loc.setNumberOptions(QLocale::OmitGroupSeparator);
197         input->setText(loc.toString(value, f, prec));
198 }
199
200
201 void doubleToWidget(QLineEdit * input, string const & value, char f, int prec)
202 {
203         doubleToWidget(input, convert<double>(value), f, prec);
204 }
205
206
207 QString formatLocFPNumber(double d)
208 {
209         QString result = toqstr(formatFPNumber(d));
210         QLocale loc;
211         result.replace('.', loc.decimalPoint());
212         return result;
213 }
214
215
216 void setValid(QWidget * widget, bool valid)
217 {
218         if (valid) {
219                 widget->setPalette(QPalette());
220         } else {
221                 QPalette pal = widget->palette();
222                 pal.setColor(QPalette::Active, QPalette::Foreground, QColor(255, 0, 0));
223                 widget->setPalette(pal);
224         }
225 }
226
227 /// wrapper to hide the change of method name to setSectionResizeMode
228 void setSectionResizeMode(QHeaderView * view,
229     int logicalIndex, QHeaderView::ResizeMode mode) {
230 #if (QT_VERSION >= 0x050000)
231         view->setSectionResizeMode(logicalIndex, mode);
232 #else
233         view->setResizeMode(logicalIndex, mode);
234 #endif
235 }
236
237 void setSectionResizeMode(QHeaderView * view, QHeaderView::ResizeMode mode) {
238 #if (QT_VERSION >= 0x050000)
239         view->setSectionResizeMode(mode);
240 #else
241         view->setResizeMode(mode);
242 #endif
243 }
244 } // namespace frontend
245
246 QString const qt_(char const * str, const char *)
247 {
248         return toqstr(_(str));
249 }
250
251
252 QString const qt_(string const & str)
253 {
254         return toqstr(_(str));
255 }
256
257
258 QString const qt_(QString const & qstr)
259 {
260         return toqstr(_(fromqstr(qstr)));
261 }
262
263
264 void rescanTexStyles(string const & arg)
265 {
266         // Run rescan in user lyx directory
267         PathChanger p(package().user_support());
268         FileName const prog = support::libFileSearch("scripts", "TeXFiles.py");
269         Systemcall one;
270         string const command = os::python() + ' ' +
271             quoteName(prog.toFilesystemEncoding()) + ' ' +
272             arg;
273         int const status = one.startscript(Systemcall::Wait, command);
274         if (status == 0)
275                 return;
276         // FIXME UNICODE
277         frontend::Alert::error(_("Could not update TeX information"),
278                 bformat(_("The script `%1$s' failed."), from_utf8(prog.absFileName())));
279 }
280
281
282 QStringList texFileList(QString const & filename)
283 {
284         QStringList list;
285         FileName const file = libFileSearch(QString(), filename);
286         if (file.empty())
287                 return list;
288
289         // FIXME Unicode.
290         vector<docstring> doclist = 
291                 getVectorFromString(file.fileContents("UTF-8"), from_ascii("\n"));
292
293         // Normalise paths like /foo//bar ==> /foo/bar
294         QSet<QString> set;
295         for (size_t i = 0; i != doclist.size(); ++i) {
296                 QString file = toqstr(doclist[i]);
297                 file.replace("\r", "");
298                 while (file.contains("//"))
299                         file.replace("//", "/");
300                 if (!file.isEmpty())
301                         set.insert(file);
302         }
303
304         // remove duplicates
305         return QList<QString>::fromSet(set);
306 }
307
308 QString const externalLineEnding(docstring const & str)
309 {
310 #ifdef Q_OS_MAC
311         // The MAC clipboard uses \r for lineendings, and we use \n
312         return toqstr(subst(str, '\n', '\r'));
313 #elif defined(Q_OS_WIN) || defined(Q_CYGWIN_WIN)
314         // Windows clipboard uses \r\n for lineendings, and we use \n
315         return toqstr(subst(str, from_ascii("\n"), from_ascii("\r\n")));
316 #else
317         return toqstr(str);
318 #endif
319 }
320
321
322 docstring const internalLineEnding(QString const & str)
323 {
324         docstring const s = subst(qstring_to_ucs4(str), 
325                                   from_ascii("\r\n"), from_ascii("\n"));
326         return subst(s, '\r', '\n');
327 }
328
329
330 QString internalPath(const QString & str)
331 {
332         return toqstr(os::internal_path(fromqstr(str)));
333 }
334
335
336 QString onlyFileName(const QString & str)
337 {
338         return toqstr(support::onlyFileName(fromqstr(str)));
339 }
340
341
342 QString onlyPath(const QString & str)
343 {
344         return toqstr(support::onlyPath(fromqstr(str)));
345 }
346
347
348 QString changeExtension(QString const & oldname, QString const & ext)
349 {
350         return toqstr(support::changeExtension(fromqstr(oldname), fromqstr(ext)));
351 }
352
353 /// Remove the extension from \p name
354 QString removeExtension(QString const & name)
355 {
356         return toqstr(support::removeExtension(fromqstr(name)));
357 }
358
359 /** Add the extension \p ext to \p name.
360  Use this instead of changeExtension if you know that \p name is without
361  extension, because changeExtension would wrongly interpret \p name if it
362  contains a dot.
363  */
364 QString addExtension(QString const & name, QString const & ext)
365 {
366         return toqstr(support::addExtension(fromqstr(name), fromqstr(ext)));
367 }
368
369 /// Return the extension of the file (not including the .)
370 QString getExtension(QString const & name)
371 {
372         return toqstr(support::getExtension(fromqstr(name)));
373 }
374
375
376 /** Convert relative path into absolute path based on a basepath.
377   If relpath is absolute, just use that.
378   If basepath doesn't exist use CWD.
379   */
380 QString makeAbsPath(QString const & relpath, QString const & base)
381 {
382         return toqstr(support::makeAbsPath(fromqstr(relpath),
383                 fromqstr(base)).absFileName());
384 }
385
386
387 /////////////////////////////////////////////////////////////////////////
388 //
389 // FileFilterList
390 //
391 /////////////////////////////////////////////////////////////////////////
392
393 /** Given a string such as
394  *      "<glob> <glob> ... *.{abc,def} <glob>",
395  *  convert the csh-style brace expresions:
396  *      "<glob> <glob> ... *.abc *.def <glob>".
397  *  Requires no system support, so should work equally on Unix, Mac, Win32.
398  */
399 static string const convert_brace_glob(string const & glob)
400 {
401         // Matches " *.{abc,def,ghi}", storing "*." as group 1 and
402         // "abc,def,ghi" as group 2, while allowing spaces in group 2.
403         static lyx::regex const glob_re(" *([^ {]*)\\{([^}]+)\\}");
404         // Matches "abc" and "abc,", storing "abc" as group 1,
405         // while ignoring surrounding spaces.
406         static lyx::regex const block_re(" *([^ ,}]+) *,? *");
407
408         string pattern;
409
410         string::const_iterator it = glob.begin();
411         string::const_iterator const end = glob.end();
412         while (true) {
413                 match_results<string::const_iterator> what;
414                 if (!regex_search(it, end, what, glob_re)) {
415                         // Ensure that no information is lost.
416                         pattern += string(it, end);
417                         break;
418                 }
419
420                 // Everything from the start of the input to
421                 // the start of the match.
422                 pattern += string(what[-1].first, what[-1].second);
423
424                 // Given " *.{abc,def}", head == "*." and tail == "abc,def".
425                 string const head = string(what[1].first, what[1].second);
426                 string const tail = string(what[2].first, what[2].second);
427
428                 // Split the ','-separated chunks of tail so that
429                 // $head{$chunk1,$chunk2} becomes "$head$chunk1 $head$chunk2".
430                 string const fmt = " " + head + "$1";
431                 pattern += regex_replace(tail, block_re, fmt);
432
433                 // Increment the iterator to the end of the match.
434                 it += distance(it, what[0].second);
435         }
436
437         return pattern;
438 }
439
440
441 struct Filter
442 {
443         /* \param description text describing the filters.
444          * \param one or more wildcard patterns, separated by
445          * whitespace.
446          */
447         Filter(docstring const & description, std::string const & globs);
448
449         docstring const & description() const { return desc_; }
450
451         QString toString() const;
452
453         docstring desc_;
454         std::vector<std::string> globs_;
455 };
456
457
458 Filter::Filter(docstring const & description, string const & globs)
459         : desc_(description)
460 {
461         typedef boost::tokenizer<boost::char_separator<char> > Tokenizer;
462         boost::char_separator<char> const separator(" ");
463
464         // Given "<glob> <glob> ... *.{abc,def} <glob>", expand to
465         //       "<glob> <glob> ... *.abc *.def <glob>"
466         string const expanded_globs = convert_brace_glob(globs);
467
468         // Split into individual globs.
469         Tokenizer const tokens(expanded_globs, separator);
470         globs_ = vector<string>(tokens.begin(), tokens.end());
471 }
472
473
474 QString Filter::toString() const
475 {
476         QString s;
477
478         bool const has_description = !desc_.empty();
479
480         if (has_description) {
481                 s += toqstr(desc_);
482                 s += " (";
483         }
484
485         for (size_t i = 0; i != globs_.size(); ++i) {
486                 if (i > 0)
487                         s += ' ';
488                 s += toqstr(globs_[i]);
489         }
490
491         if (has_description)
492                 s += ')';
493         return s;
494 }
495
496
497 /** \c FileFilterList parses a Qt-style list of available file filters
498  *  to generate the corresponding vector.
499  *  For example "TeX documents (*.tex);;LyX Documents (*.lyx)"
500  *  will be parsed to fill a vector of size 2, whilst "*.{p[bgp]m} *.pdf"
501  *  will result in a vector of size 1 in which the description field is empty.
502  */
503 struct FileFilterList
504 {
505         // FIXME UNICODE: globs_ should be unicode...
506         /** \param qt_style_filter a list of available file filters.
507          *  Eg. "TeX documents (*.tex);;LyX Documents (*.lyx)".
508          *  The "All files (*)" filter is always added to the list.
509          */
510         explicit FileFilterList(docstring const & qt_style_filter =
511                                 docstring());
512
513         typedef std::vector<Filter>::size_type size_type;
514
515         bool empty() const { return filters_.empty(); }
516         size_type size() const { return filters_.size(); }
517         Filter & operator[](size_type i) { return filters_[i]; }
518         Filter const & operator[](size_type i) const { return filters_[i]; }
519
520         void parse_filter(std::string const & filter);
521         std::vector<Filter> filters_;
522 };
523
524
525 FileFilterList::FileFilterList(docstring const & qt_style_filter)
526 {
527         // FIXME UNICODE
528         string const filter = to_utf8(qt_style_filter)
529                 + (qt_style_filter.empty() ? string() : ";;")
530                 + to_utf8(_("All Files "))
531 #if defined(_WIN32)             
532                 + ("(*.*)");
533 #else
534                 + ("(*)");
535 #endif
536
537         // Split data such as "TeX documents (*.tex);;LyX Documents (*.lyx)"
538         // into individual filters.
539         static lyx::regex const separator_re(";;");
540
541         string::const_iterator it = filter.begin();
542         string::const_iterator const end = filter.end();
543         while (true) {
544                 match_results<string::const_iterator> what;
545
546                 if (!lyx::regex_search(it, end, what, separator_re)) {
547                         parse_filter(string(it, end));
548                         break;
549                 }
550
551                 // Everything from the start of the input to
552                 // the start of the match.
553                 parse_filter(string(what[-1].first, what[-1].second));
554
555                 // Increment the iterator to the end of the match.
556                 it += distance(it, what[0].second);
557         }
558 }
559
560
561 void FileFilterList::parse_filter(string const & filter)
562 {
563         // Matches "TeX documents (plain) (*.tex)",
564         // storing "TeX documents (plain) " as group 1 and "*.tex" as group 2.
565         static lyx::regex const filter_re("(.*)\\(([^()]+)\\) *$");
566
567         match_results<string::const_iterator> what;
568         if (!lyx::regex_search(filter, what, filter_re)) {
569                 // Just a glob, no description.
570                 filters_.push_back(Filter(docstring(), trim(filter)));
571         } else {
572                 // FIXME UNICODE
573                 docstring const desc = from_utf8(string(what[1].first, what[1].second));
574                 string const globs = string(what[2].first, what[2].second);
575                 filters_.push_back(Filter(trim(desc), trim(globs)));
576         }
577 }
578
579
580 /** \returns the equivalent of the string passed in
581  *  although any brace expressions are expanded.
582  *  (E.g. "*.{png,jpg}" -> "*.png *.jpg")
583  */
584 QStringList fileFilters(QString const & desc)
585 {
586         // we have: "*.{gif,png,jpg,bmp,pbm,ppm,tga,tif,xpm,xbm}"
587         // but need:  "*.cpp;*.cc;*.C;*.cxx;*.c++"
588         FileFilterList filters(qstring_to_ucs4(desc));
589         //LYXERR0("DESC: " << desc);
590         QStringList list;
591         for (size_t i = 0; i != filters.filters_.size(); ++i) {
592                 QString f = filters.filters_[i].toString();
593                 //LYXERR0("FILTER: " << f);
594                 list.append(f);
595         }
596         return list;
597 }
598
599
600 QString guiName(string const & type, BufferParams const & bp)
601 {
602         if (type == "tableofcontents")
603                 return qt_("Table of Contents");
604         if (type == "child")
605                 return qt_("Child Documents");
606         if (type == "graphics")
607                 return qt_("Graphics");
608         if (type == "equation")
609                 return qt_("Equations");
610         if (type == "external")
611                 return qt_("External material");
612         if (type == "footnote")
613                 return qt_("Footnotes");
614         if (type == "listing")
615                 return qt_("Listings");
616         if (type == "index")
617                 return qt_("Index Entries");
618         if (type == "marginalnote")
619                 return qt_("Marginal notes");
620         if (type == "math-macro")
621                 return qt_("Math macros");
622         if (type == "nomencl")
623                 return qt_("Nomenclature Entries");
624         if (type == "note")
625                 return qt_("Notes");
626         if (type == "citation")
627                 return qt_("Citations");
628         if (type == "label")
629                 return qt_("Labels and References");
630         if (type == "branch")
631                 return qt_("Branches");
632         if (type == "change")
633                 return qt_("Changes");
634         if (type == "senseless")
635                 return qt_("Senseless");
636         if (prefixIs(type, "index:")) {
637                 string const itype = split(type, ':');
638                 IndicesList const & indiceslist = bp.indiceslist();
639                 Index const * index = indiceslist.findShortcut(from_utf8(itype));
640                 docstring indextype = _("unknown type!");
641                 if (index)
642                         indextype = index->index();
643                 return toqstr(bformat(_("Index Entries (%1$s)"), indextype));
644         }
645
646         FloatList const & floats = bp.documentClass().floats();
647         if (floats.typeExist(type))
648                 return qt_(floats.getType(type).listName());
649
650         return qt_(type);
651 }
652
653
654 } // namespace lyx