X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Ffrontends%2Fqt4%2Fqt_helpers.cpp;h=7f4c5d8fda1f8e1cccb18cc18553b97d3d58643c;hb=ee7dd4a11ea21851e7e32164c66b37d3bc8ac31d;hp=5cb11cbea53001da275bd0a9ee704090180dab24;hpb=d1aff33dd59115e8c2bf17cd7fe63709db8de35b;p=lyx.git diff --git a/src/frontends/qt4/qt_helpers.cpp b/src/frontends/qt4/qt_helpers.cpp index 5cb11cbea5..7f4c5d8fda 100644 --- a/src/frontends/qt4/qt_helpers.cpp +++ b/src/frontends/qt4/qt_helpers.cpp @@ -4,7 +4,7 @@ * Licence details can be found in the file COPYING. * * \author Dekel Tsur - * \author Jürgen Spitzmüller + * \author Jürgen Spitzmüller * \author Richard Heck * * Full author contact details are available in file CREDITS. @@ -19,9 +19,13 @@ #include "frontends/alert.h" +#include "BufferParams.h" +#include "FloatList.h" #include "Language.h" #include "Length.h" +#include "TextClass.h" +#include "support/convert.h" #include "support/debug.h" #include "support/filetools.h" #include "support/foreach.h" @@ -36,6 +40,7 @@ #include #include #include +#include #include #include @@ -43,6 +48,12 @@ #include #include +// for FileFilter. +// FIXME: Remove +#include "support/regex.h" +#include + + using namespace std; using namespace lyx::support; @@ -54,6 +65,7 @@ FileName libFileSearch(QString const & dir, QString const & name, return support::libFileSearch(fromqstr(dir), fromqstr(name), fromqstr(ext)); } + namespace frontend { string widgetsToLength(QLineEdit const * input, LengthCombo const * combo) @@ -68,7 +80,7 @@ string widgetsToLength(QLineEdit const * input, LengthCombo const * combo) Length::UNIT const unit = combo->currentLengthItem(); - return Length(length.toDouble(), unit).asString(); + return Length(length.trimmed().toDouble(), unit).asString(); } @@ -82,9 +94,16 @@ Length widgetsToLength(QLineEdit const * input, QComboBox const * combo) if (isValidGlueLength(fromqstr(length))) return Length(fromqstr(length)); - Length::UNIT const unit = unitFromString(fromqstr(combo->currentText())); + Length::UNIT unit = Length::UNIT_NONE; + QString const item = combo->currentText(); + for (int i = 0; i < num_units; i++) { + if (qt_(lyx::unit_name_gui[i]) == item) { + unit = unitFromString(unit_name[i]); + break; + } + } - return Length(length.toDouble(), unit); + return Length(length.trimmed().toDouble(), unit); } @@ -92,7 +111,9 @@ void lengthToWidgets(QLineEdit * input, LengthCombo * combo, Length const & len, Length::UNIT /*defaultUnit*/) { combo->setCurrentItem(len.unit()); - input->setText(QString::number(Length(len).value())); + QLocale loc; + loc.setNumberOptions(QLocale::OmitGroupSeparator); + input->setText(loc.toString(Length(len).value())); } @@ -113,13 +134,44 @@ void lengthToWidgets(QLineEdit * input, LengthCombo * combo, } -void lengthAutoToWidgets(QLineEdit * input, LengthCombo * combo, - Length const & len, Length::UNIT defaultUnit) +void lengthToWidgets(QLineEdit * input, LengthCombo * combo, + docstring const & len, Length::UNIT defaultUnit) +{ + lengthToWidgets(input, combo, to_utf8(len), defaultUnit); +} + + +double widgetToDouble(QLineEdit const * input) +{ + QString const text = input->text(); + if (text.isEmpty()) + return 0.0; + + return text.trimmed().toDouble(); +} + + +string widgetToDoubleStr(QLineEdit const * input) +{ + QString const text = input->text(); + if (text.isEmpty()) + return string(); + + return convert(text.trimmed().toDouble()); +} + + +void doubleToWidget(QLineEdit * input, double const & value, char f, int prec) { - if (len.value() == 0) - lengthToWidgets(input, combo, "auto", defaultUnit); - else - lengthToWidgets(input, combo, len, defaultUnit); + QLocale loc; + loc.setNumberOptions(QLocale::OmitGroupSeparator); + input->setText(loc.toString(value, f, prec)); +} + + +void doubleToWidget(QLineEdit * input, string const & value, char f, int prec) +{ + doubleToWidget(input, convert(value), f, prec); } @@ -147,78 +199,12 @@ QString const qt_(string const & str) return toqstr(_(str)); } -namespace { - -class Sorter -{ -public: -#if !defined(USE_WCHAR_T) && defined(__GNUC__) - bool operator()(LanguagePair const & lhs, LanguagePair const & rhs) const - { - return lhs.first < rhs.first; - } -#else - Sorter() : loc_ok(true) - { - try { - loc_ = locale(""); - } catch (...) { - loc_ok = false; - } - } - - bool operator()(LanguagePair const & lhs, LanguagePair const & rhs) const - { - // FIXME: would that be "QString::localeAwareCompare()"? - if (loc_ok) - return loc_(fromqstr(lhs.first), fromqstr(rhs.first)); - else - return lhs.first < rhs.first; - } -private: - locale loc_; - bool loc_ok; -#endif -}; - - -} // namespace anon - - -QList languageData(bool character_dlg) -{ - size_t const offset = character_dlg ? 2 : 0; - vector langs(languages.size() + offset); - - if (character_dlg) { - langs[0].first = qt_("No change"); - langs[0].second = "ignore"; - langs[1].first = qt_("Reset"); - langs[1].second = "reset"; - } - - Languages::const_iterator it = languages.begin(); - for (size_t i = 0; i != languages.size(); ++i, ++it) { - langs[i + offset].first = qt_(it->second.display()); - langs[i + offset].second = toqstr(it->second.lang()); - } - - // Don't sort "ignore" and "reset" - vector::iterator begin = langs.begin() + offset; - sort(begin, langs.end(), Sorter()); - - QList list; - foreach (LanguagePair const & l, langs) - list.append(l); - return list; -} - void rescanTexStyles() { // Run rescan in user lyx directory PathChanger p(package().user_support()); - FileName const command = libFileSearch("scripts", "TeXFiles.py"); + FileName const command = support::libFileSearch("scripts", "TeXFiles.py"); Systemcall one; int const status = one.startscript(Systemcall::Wait, os::python() + ' ' + @@ -227,7 +213,7 @@ void rescanTexStyles() return; // FIXME UNICODE frontend::Alert::error(_("Could not update TeX information"), - bformat(_("The script `%s' failed."), from_utf8(command.absFilename()))); + bformat(_("The script `%1$s' failed."), from_utf8(command.absFileName()))); } @@ -257,6 +243,27 @@ QStringList texFileList(QString const & filename) return QList::fromSet(set); } +QString const externalLineEnding(docstring const & str) +{ +#ifdef Q_WS_MACX + // The MAC clipboard uses \r for lineendings, and we use \n + return toqstr(subst(str, '\n', '\r')); +#elif defined(Q_WS_WIN) + // Windows clipboard uses \r\n for lineendings, and we use \n + return toqstr(subst(str, from_ascii("\n"), from_ascii("\r\n"))); +#else + return toqstr(str); +#endif +} + + +docstring const internalLineEnding(QString const & str) +{ + docstring const s = subst(qstring_to_ucs4(str), + from_ascii("\r\n"), from_ascii("\n")); + return subst(s, '\r', '\n'); +} + QString internalPath(const QString & str) { @@ -264,9 +271,9 @@ QString internalPath(const QString & str) } -QString onlyFilename(const QString & str) +QString onlyFileName(const QString & str) { - return toqstr(support::onlyFilename(fromqstr(str))); + return toqstr(support::onlyFileName(fromqstr(str))); } @@ -303,4 +310,266 @@ QString getExtension(QString const & name) return toqstr(support::getExtension(fromqstr(name))); } + +/** Convert relative path into absolute path based on a basepath. + If relpath is absolute, just use that. + If basepath doesn't exist use CWD. + */ +QString makeAbsPath(QString const & relpath, QString const & base) +{ + return toqstr(support::makeAbsPath(fromqstr(relpath), + fromqstr(base)).absFileName()); +} + + +///////////////////////////////////////////////////////////////////////// +// +// FileFilterList +// +///////////////////////////////////////////////////////////////////////// + +/** Given a string such as + * " ... *.{abc,def} ", + * convert the csh-style brace expresions: + * " ... *.abc *.def ". + * Requires no system support, so should work equally on Unix, Mac, Win32. + */ +static string const convert_brace_glob(string const & glob) +{ + // Matches " *.{abc,def,ghi}", storing "*." as group 1 and + // "abc,def,ghi" as group 2. + static lyx::regex const glob_re(" *([^ {]*)\\{([^ }]+)\\}"); + // Matches "abc" and "abc,", storing "abc" as group 1. + static lyx::regex const block_re("([^,}]+),?"); + + string pattern; + + string::const_iterator it = glob.begin(); + string::const_iterator const end = glob.end(); + while (true) { + match_results what; + if (!regex_search(it, end, what, glob_re)) { + // Ensure that no information is lost. + pattern += string(it, end); + break; + } + + // Everything from the start of the input to + // the start of the match. + pattern += string(what[-1].first, what[-1].second); + + // Given " *.{abc,def}", head == "*." and tail == "abc,def". + string const head = string(what[1].first, what[1].second); + string const tail = string(what[2].first, what[2].second); + + // Split the ','-separated chunks of tail so that + // $head{$chunk1,$chunk2} becomes "$head$chunk1 $head$chunk2". + string const fmt = " " + head + "$1"; + pattern += regex_replace(tail, block_re, fmt); + + // Increment the iterator to the end of the match. + it += distance(it, what[0].second); + } + + return pattern; +} + + +struct Filter +{ + /* \param description text describing the filters. + * \param one or more wildcard patterns, separated by + * whitespace. + */ + Filter(docstring const & description, std::string const & globs); + + docstring const & description() const { return desc_; } + + QString toString() const; + + docstring desc_; + std::vector globs_; +}; + + +Filter::Filter(docstring const & description, string const & globs) + : desc_(description) +{ + typedef boost::tokenizer > Tokenizer; + boost::char_separator const separator(" "); + + // Given " ... *.{abc,def} ", expand to + // " ... *.abc *.def " + string const expanded_globs = convert_brace_glob(globs); + + // Split into individual globs. + vector matches; + Tokenizer const tokens(expanded_globs, separator); + globs_ = vector(tokens.begin(), tokens.end()); +} + + +QString Filter::toString() const +{ + QString s; + + bool const has_description = desc_.empty(); + + if (has_description) { + s += toqstr(desc_); + s += " ("; + } + + for (size_t i = 0; i != globs_.size(); ++i) { + if (i > 0) + s += ' '; + s += toqstr(globs_[i]); + } + + if (has_description) + s += ')'; + return s; +} + + +/** \c FileFilterList parses a Qt-style list of available file filters + * to generate the corresponding vector. + * For example "TeX documents (*.tex);;LyX Documents (*.lyx)" + * will be parsed to fill a vector of size 2, whilst "*.{p[bgp]m} *.pdf" + * will result in a vector of size 1 in which the description field is empty. + */ +struct FileFilterList +{ + // FIXME UNICODE: globs_ should be unicode... + /** \param qt_style_filter a list of available file filters. + * Eg. "TeX documents (*.tex);;LyX Documents (*.lyx)". + * The "All files (*)" filter is always added to the list. + */ + explicit FileFilterList(docstring const & qt_style_filter = + docstring()); + + typedef std::vector::size_type size_type; + + bool empty() const { return filters_.empty(); } + size_type size() const { return filters_.size(); } + Filter & operator[](size_type i) { return filters_[i]; } + Filter const & operator[](size_type i) const { return filters_[i]; } + + void parse_filter(std::string const & filter); + std::vector filters_; +}; + + +FileFilterList::FileFilterList(docstring const & qt_style_filter) +{ + // FIXME UNICODE + string const filter = to_utf8(qt_style_filter) + + (qt_style_filter.empty() ? string() : ";;") + + to_utf8(_("All Files ")) +#if defined(_WIN32) + + ("(*.*)"); +#else + + ("(*)"); +#endif + + // Split data such as "TeX documents (*.tex);;LyX Documents (*.lyx)" + // into individual filters. + static lyx::regex const separator_re(";;"); + + string::const_iterator it = filter.begin(); + string::const_iterator const end = filter.end(); + while (true) { + match_results what; + + if (!lyx::regex_search(it, end, what, separator_re)) { + parse_filter(string(it, end)); + break; + } + + // Everything from the start of the input to + // the start of the match. + parse_filter(string(what[-1].first, what[-1].second)); + + // Increment the iterator to the end of the match. + it += distance(it, what[0].second); + } +} + + +void FileFilterList::parse_filter(string const & filter) +{ + // Matches "TeX documents (*.tex)", + // storing "TeX documents " as group 1 and "*.tex" as group 2. + static lyx::regex const filter_re("([^(]*)\\(([^)]+)\\) *$"); + + match_results what; + if (!lyx::regex_search(filter, what, filter_re)) { + // Just a glob, no description. + filters_.push_back(Filter(docstring(), trim(filter))); + } else { + // FIXME UNICODE + docstring const desc = from_utf8(string(what[1].first, what[1].second)); + string const globs = string(what[2].first, what[2].second); + filters_.push_back(Filter(trim(desc), trim(globs))); + } +} + + +/** \returns the equivalent of the string passed in + * although any brace expressions are expanded. + * (E.g. "*.{png,jpg}" -> "*.png *.jpg") + */ +QStringList fileFilters(QString const & desc) +{ + // we have: "*.{gif,png,jpg,bmp,pbm,ppm,tga,tif,xpm,xbm}" + // but need: "*.cpp;*.cc;*.C;*.cxx;*.c++" + FileFilterList filters(qstring_to_ucs4(desc)); + //LYXERR0("DESC: " << desc); + QStringList list; + for (size_t i = 0; i != filters.filters_.size(); ++i) { + QString f = filters.filters_[i].toString(); + //LYXERR0("FILTER: " << f); + list.append(f); + } + return list; +} + + +QString guiName(string const & type, BufferParams const & bp) +{ + if (type == "tableofcontents") + return qt_("Table of Contents"); + if (type == "child") + return qt_("Child Documents"); + if (type == "graphics") + return qt_("List of Graphics"); + if (type == "equation") + return qt_("List of Equations"); + if (type == "footnote") + return qt_("List of Footnotes"); + if (type == "listing") + return qt_("List of Listings"); + if (type == "index") + return qt_("List of Indexes"); + if (type == "marginalnote") + return qt_("List of Marginal notes"); + if (type == "note") + return qt_("List of Notes"); + if (type == "citation") + return qt_("List of Citations"); + if (type == "label") + return qt_("Labels and References"); + if (type == "branch") + return qt_("List of Branches"); + if (type == "change") + return qt_("List of Changes"); + + FloatList const & floats = bp.documentClass().floats(); + if (floats.typeExist(type)) + return qt_(floats.getType(type).listName()); + + return qt_(type); +} + + } // namespace lyx