X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Ffrontends%2Fqt4%2Fqt_helpers.cpp;h=92a052048747837b018e33543298cf6052cf0550;hb=425d092204118ea6c24c28e85fdf03fcf2bb51a4;hp=d62bf9015b8b64db7f8baca20d2f65c373ea0f61;hpb=88293cbcfb546a8aa5484f2c62a8b9b3ce3b4317;p=lyx.git diff --git a/src/frontends/qt4/qt_helpers.cpp b/src/frontends/qt4/qt_helpers.cpp index d62bf9015b..92a0520487 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,11 +19,16 @@ #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" #include "support/gettext.h" #include "support/lstrings.h" #include "support/lyxalgo.h" @@ -32,21 +37,35 @@ #include "support/Path.h" #include "support/Systemcall.h" -#include #include -#include +#include #include - -#include +#include +#include +#include #include #include #include +// for FileFilter. +// FIXME: Remove +#include +#include + + using namespace std; using namespace lyx::support; namespace lyx { + +FileName libFileSearch(QString const & dir, QString const & name, + QString const & ext) +{ + return support::libFileSearch(fromqstr(dir), fromqstr(name), fromqstr(ext)); +} + + namespace frontend { string widgetsToLength(QLineEdit const * input, LengthCombo const * combo) @@ -61,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(); } @@ -75,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); } @@ -85,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())); } @@ -106,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) { - if (len.value() == 0) - lengthToWidgets(input, combo, "auto", defaultUnit); - else - lengthToWidgets(input, combo, len, defaultUnit); + 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) +{ + 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); } @@ -140,77 +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 { - if (loc_ok) - return loc_(lhs.first, rhs.first); - else - return lhs.first < rhs.first; - } -private: - locale loc_; - bool loc_ok; -#endif -}; - - -} // namespace anon - - -vector const getLanguageData(bool character_dlg) -{ - size_t const size = languages.size() + (character_dlg ? 2 : 0); - - vector langs(size); - - if (character_dlg) { - langs[0].first = _("No change"); - langs[0].second = "ignore"; - langs[1].first = _("Reset"); - langs[1].second = "reset"; - } - - size_t i = character_dlg ? 2 : 0; - for (Languages::const_iterator cit = languages.begin(); - cit != languages.end(); ++cit) { - langs[i].first = _(cit->second.display()); - langs[i].second = cit->second.lang(); - ++i; - } - - // Don't sort "ignore" and "reset" - vector::iterator begin = character_dlg ? - langs.begin() + 2 : langs.begin(); - - sort(begin, langs.end(), Sorter()); - - return langs; -} 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() + ' ' + @@ -219,31 +213,55 @@ 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()))); } -void getTexFileList(string const & filename, vector & list) +QStringList texFileList(QString const & filename) { - list.clear(); - FileName const file = libFileSearch("", filename); + QStringList list; + FileName const file = libFileSearch(QString(), filename); if (file.empty()) - return; + return list; // FIXME Unicode. vector doclist = getVectorFromString(file.fileContents("UTF-8"), from_ascii("\n")); // Normalise paths like /foo//bar ==> /foo/bar - boost::RegEx regex("/{2,}"); - vector::iterator it = doclist.begin(); - vector::iterator end = doclist.end(); - for (; it != end; ++it) - list.push_back(regex.Merge(to_utf8(*it), "/")); + QSet set; + for (size_t i = 0; i != doclist.size(); ++i) { + QString file = toqstr(doclist[i]); + file.replace("\r", ""); + while (file.contains("//")) + file.replace("//", "/"); + if (!file.isEmpty()) + set.insert(file); + } - // remove empty items and duplicates - list.erase(remove(list.begin(), list.end(), ""), list.end()); - eliminate_duplicates(list); + // remove duplicates + 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'); } @@ -264,4 +282,294 @@ QString onlyPath(const QString & str) return toqstr(support::onlyPath(fromqstr(str))); } + +QString changeExtension(QString const & oldname, QString const & ext) +{ + return toqstr(support::changeExtension(fromqstr(oldname), fromqstr(ext))); +} + +/// Remove the extension from \p name +QString removeExtension(QString const & name) +{ + return toqstr(support::removeExtension(fromqstr(name))); +} + +/** Add the extension \p ext to \p name. + Use this instead of changeExtension if you know that \p name is without + extension, because changeExtension would wrongly interpret \p name if it + contains a dot. + */ +QString addExtension(QString const & name, QString const & ext) +{ + return toqstr(support::addExtension(fromqstr(name), fromqstr(ext))); +} + +/// Return the extension of the file (not including the .) +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 boost::regex const glob_re(" *([^ {]*)\\{([^ }]+)\\}"); + // Matches "abc" and "abc,", storing "abc" as group 1. + static boost::regex const block_re("([^,}]+),?"); + + string pattern; + + string::const_iterator it = glob.begin(); + string::const_iterator const end = glob.end(); + while (true) { + boost::match_results what; + if (!boost::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 += boost::regex_merge(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 boost::regex const separator_re(";;"); + + string::const_iterator it = filter.begin(); + string::const_iterator const end = filter.end(); + while (true) { + boost::match_results what; + + if (!boost::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 boost::regex const filter_re("([^(]*)\\(([^)]+)\\) *$"); + + boost::match_results what; + if (!boost::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