X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Ffrontends%2Fxforms%2Fxforms_helpers.C;h=50fb6409d4fb85485fd65cbb49a8008bd56552fa;hb=37e82a546392d43f787826b85481a11f2a27af15;hp=72d346f4ac09604ddce881bba030efeb20922fdd;hpb=4505b2f7b35d2d1e7f48128c41d3797dbd53fe97;p=lyx.git diff --git a/src/frontends/xforms/xforms_helpers.C b/src/frontends/xforms/xforms_helpers.C index 72d346f4ac..50fb6409d4 100644 --- a/src/frontends/xforms/xforms_helpers.C +++ b/src/frontends/xforms/xforms_helpers.C @@ -1,187 +1,381 @@ -/** Collection of some useful xform helper functions +/** + * \file xforms_helpers.C + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Angus Leeming + * + * Full author contact details are available in file CREDITS. */ #include -#include FORMS_H_LOCATION - -#include // ofstream -#include - -#ifdef __GNUG_ -#pragma implementation -#endif - #include "xforms_helpers.h" + +#include "debug.h" +#include "gettext.h" +#include "lengthcommon.h" +#include "lyxgluelength.h" #include "lyxlex.h" -#include "filedlg.h" // LyXFileDlg + #include "support/FileInfo.h" #include "support/filetools.h" -#include "lyx_gui_misc.h" // WriteAlert -#include "gettext.h" +#include "support/lstrings.h" // frontStrip, strip +#include "support/tostr.h" + +#include "lyx_forms.h" +#include "combox.h" + +#include + +#include + +using std::make_pair; using std::ofstream; -using std::pair; using std::vector; +using std::string; + +namespace lyx { + +using support::AbsolutePath; +using support::FileInfo; +using support::isStrDbl; +using support::OnlyPath; +using support::subst; +using support::trim; + +namespace frontend { + +std::string const buildChoiceLengthString() +{ + string data; + for (int i = 0; i != num_units; ++i) { + if (i != 0) + data += "|"; + data += subst(unit_name_gui[i], "%", "%%"); + } + return data; +} + + +bool isActive(FL_OBJECT * ob) +{ + return ob && ob->active > 0; +} + + +std::pair parse_shortcut(string const & str) +{ + string::size_type i = str.find_first_of("&"); + if (i == string::npos || i == str.length() - 1) + return make_pair(str, string()); + + // FIXME: handle && + + string::value_type c = str[i + 1]; + return make_pair(str.substr(0, i) + str.substr(i + 1), + string("#") + c); +} + + +// A wrapper for the xforms routine, but this one accepts uint args +unsigned long fl_getmcolor(int i, + unsigned int * r, unsigned int * g, unsigned int * b) +{ + int r2, g2, b2; + unsigned long ret_val = ::fl_getmcolor(i, &r2, &g2, &b2); + *r = r2; + *g = g2; + *b = b2; + return ret_val; +} + // Set an FL_OBJECT to activated or deactivated void setEnabled(FL_OBJECT * ob, bool enable) { if (enable) { fl_activate_object(ob); - fl_set_object_lcol(ob, FL_BLACK); + fl_set_object_lcol(ob, FL_LCOL); } else { fl_deactivate_object(ob); fl_set_object_lcol(ob, FL_INACTIVE); } } - -// Take a string and add breaks so that it fits into a desired label width, w -string formatted(string const & sin, int w, int size, int style) + +// Given an fl_choice or an fl_browser, create a vector of its entries +vector const getVector(FL_OBJECT * ob) { - string sout; - if (sin.empty()) return sout; - - // break sin up into a vector of individual words - vector sentence; - string word; - for (string::const_iterator sit = sin.begin(); - sit != sin.end(); ++sit) { - if ((*sit) == ' ' || (*sit) == '\n') { - sentence.push_back(word); - word.erase(); - } else { - word += (*sit); + vector vec; + + switch (ob->objclass) { + case FL_CHOICE: + for(int i = 0; i < fl_get_choice_maxitems(ob); ++i) { + string const text = fl_get_choice_item_text(ob, i+1); + vec.push_back(trim(text)); + } + break; + case FL_BROWSER: + for(int i = 0; i < fl_get_browser_maxline(ob); ++i) { + string const text = fl_get_browser_line(ob, i+1); + vec.push_back(trim(text)); } + break; + default: + BOOST_ASSERT(false); } - // Flush remaining contents of word - if (!word.empty() ) sentence.push_back(word); - string line, l1; - for (vector::const_iterator vit = sentence.begin(); - vit != sentence.end(); ++vit) { - if (!l1.empty() ) l1 += ' '; - l1 += (*vit); - int length = fl_get_string_width(style, size, l1.c_str(), - int(l1.length())); - if (length >= w) { - if (!sout.empty() ) sout += '\n'; - sout += line; - l1 = (*vit); - } + return vec; +} + + +/// +string const getString(FL_OBJECT * ob, int line) +{ + // Negative line value does not make sense. + BOOST_ASSERT(line >= 0); + + char const * tmp = 0; + switch (ob->objclass) { + case FL_INPUT: + tmp = fl_get_input(ob); + break; - line = l1; + case FL_BROWSER: + if (line == 0) + line = fl_get_browser(ob); + + if (line >= 1 && line <= fl_get_browser_maxline(ob)) + tmp = fl_get_browser_line(ob, line); + break; + + case FL_CHOICE: + if (line == 0) + line = fl_get_choice(ob); + + if (line >= 1 && line <= fl_get_choice_maxitems(ob)) + tmp = fl_get_choice_item_text(ob, line); + break; + + case FL_COMBOX: + tmp = fl_get_combox_text(ob); + break; + + default: + BOOST_ASSERT(false); } - // Flush remaining contents of line - if (!line.empty()) { - if (!sout.empty() ) sout += '\n'; - sout += line; + + return tmp ? trim(tmp) : string(); +} + +string getLengthFromWidgets(FL_OBJECT * input, FL_OBJECT * choice) +{ + // Paranoia check + BOOST_ASSERT(input && input->objclass == FL_INPUT && + choice && choice->objclass == FL_CHOICE); + + string const length = trim(fl_get_input(input)); + if (length.empty()) + return string(); + + // don't return unit-from-choice if the input(field) contains a unit + if (isValidGlueLength(length)) + return length; + + string unit = trim(fl_get_choice_text(choice)); + unit = subst(unit, "%%", "%"); + + return length + unit; +} + + +void updateWidgetsFromLengthString(FL_OBJECT * input, FL_OBJECT * choice, + string const & str, + string const & default_unit) +{ + // Paranoia check + BOOST_ASSERT(input && input->objclass == FL_INPUT && + choice && choice->objclass == FL_CHOICE); + + // use input field only for gluelengths + if (!isValidLength(str) && !isStrDbl(str)) { + fl_set_input(input, str.c_str()); + // we assume that "default_unit" is in the choice as "we" + // have control over that! + // No need to check for its presence in the choice, therefore. + fl_set_choice_text(choice, default_unit.c_str()); + } else { + updateWidgetsFromLength(input, choice, + LyXLength(str), default_unit); } - - return sout; } -string const browseFile(string const & filename, - string const & title, - string const & pattern, - pair const & dir1, - pair const & dir2) +void updateWidgetsFromLength(FL_OBJECT * input, FL_OBJECT * choice, + LyXLength const & len, + string const & default_unit) { - string lastPath = "."; - if (!filename.empty()) lastPath = OnlyPath(filename); + // Paranoia check + BOOST_ASSERT(input && input->objclass == FL_INPUT && + choice && choice->objclass == FL_CHOICE); - LyXFileDlg fileDlg; + if (len.empty()) { + fl_set_input(input, ""); + fl_set_choice_text(choice, default_unit.c_str()); + } else { + fl_set_input(input, tostr(len.value()).c_str()); - if (!dir1.second.empty()) { - FileInfo fileInfo(dir1.second); - if (fileInfo.isOK() && fileInfo.isDir()) - fileDlg.SetButton(0, _(dir1.first), dir1.second); - } + // Set the choice to the desired unit, if present in the choice. + // Else set the choice to the default unit. + string const unit = subst(stringFromUnit(len.unit()),"%","%%"); - if (!dir2.second.empty()) { - FileInfo fileInfo(dir2.second); - if (fileInfo.isOK() && fileInfo.isDir()) - fileDlg.SetButton(1, _(dir2.first), dir2.second); + vector const vec = getVector(choice); + vector::const_iterator it = + std::find(vec.begin(), vec.end(), unit); + if (it != vec.end()) { + fl_set_choice_text(choice, unit.c_str()); + } else { + fl_set_choice_text(choice, default_unit.c_str()); + } } +} - bool error = false; - string buf; - do { - string p = fileDlg.Select(_(title), - lastPath, - pattern, OnlyFilename(filename)); - if (p.empty()) return p; +// Take a string and add breaks so that it fits into a desired label width, w +string formatted(string const & sin, int w, int size, int style) +{ + string sout; + if (sin.empty()) + return sout; + + string::size_type curpos = 0; + string line; + for(;;) { + string::size_type const nxtpos1 = sin.find(' ', curpos); + string::size_type const nxtpos2 = sin.find('\n', curpos); + string::size_type const nxtpos = std::min(nxtpos1, nxtpos2); + + string const word = nxtpos == string::npos ? + sin.substr(curpos) : sin.substr(curpos, nxtpos-curpos); - lastPath = OnlyPath(p); + bool const newline = (nxtpos2 != string::npos && + nxtpos2 < nxtpos1); + + string const line_plus_word = + line.empty() ? word : line + ' ' + word; + + int const length = + fl_get_string_width(style, size, + line_plus_word.c_str(), + int(line_plus_word.length())); + + if (length >= w) { + sout += line + '\n'; + if (newline) { + sout += word + '\n'; + line.erase(); + } else { + line = word; + } + + } else if (newline) { + sout += line_plus_word + '\n'; + line.erase(); - if (p.find_first_of("#~$% ") != string::npos) { - WriteAlert(_("Filename can't contain any " - "of these characters:"), - _("space, '#', '~', '$' or '%'.")); - error = true; } else { - error = false; - buf = p; + if (!line.empty()) + line += ' '; + line += word; + } + + if (nxtpos == string::npos) { + if (!line.empty()) + sout += line; + break; } - } while (error); - return buf; + curpos = nxtpos+1; + } + + return sout; } +void setCursorColor(int color) +{ + fl_set_cursor_color(FL_DEFAULT_CURSOR, color, FL_WHITE); + fl_set_cursor_color(XC_xterm, color, FL_WHITE); + fl_set_cursor_color(XC_watch, color, FL_WHITE); + fl_set_cursor_color(XC_sb_right_arrow, color, FL_WHITE); +} + + +namespace { + // sorted by hand to prevent LyXLex from complaining on read(). -static keyword_item xformTags[] = { - { "\\gui_background", FL_COL1 }, + { "\\gui_background", FL_COL1 }, { "\\gui_buttonbottom", FL_BOTTOM_BCOL }, - { "\\gui_buttonleft", FL_LEFT_BCOL }, - { "\\gui_buttonright", FL_RIGHT_BCOL }, - { "\\gui_buttontop", FL_TOP_BCOL }, - { "\\gui_inactive", FL_INACTIVE }, - { "\\gui_push_button", FL_YELLOW }, - { "\\gui_selected", FL_MCOL }, - { "\\gui_text", FL_BLACK } + { "\\gui_buttonleft", FL_LEFT_BCOL }, + { "\\gui_buttonright", FL_RIGHT_BCOL }, + { "\\gui_buttontop", FL_TOP_BCOL }, + { "\\gui_inactive", FL_INACTIVE }, + { "\\gui_pointer", FL_FREE_COL16 }, + { "\\gui_push_button", FL_YELLOW }, + { "\\gui_selected", FL_MCOL }, + { "\\gui_text", FL_BLACK } }; -static const int xformCount = sizeof(xformTags) / sizeof(keyword_item); +const int xformCount = sizeof(xformTags) / sizeof(keyword_item); + +} // namespace anon bool XformsColor::read(string const & filename) { + FileInfo const f(filename); LyXLex lexrc(xformTags, xformCount); - if (!lexrc.setFile(filename)) + if (f.readable() && !lexrc.setFile(filename)) { + lyxerr << "XformsColor::read(" << filename << ")\n" + << _("Failed to open file.") << std::endl; return false; + } - while (lexrc.IsOK()) { + while (lexrc.isOK()) { int const le = lexrc.lex(); switch (le) { case LyXLex::LEX_UNDEF: lexrc.printError("Unknown tag `$$Token'"); - continue; + continue; case LyXLex::LEX_FEOF: continue; default: break; } + string const tag = lexrc.getString(); + RGBColor col; if (!lexrc.next()) break; - col.r = lexrc.GetInteger(); + col.r = lexrc.getInteger(); if (!lexrc.next()) break; - col.g = lexrc.GetInteger(); + col.g = lexrc.getInteger(); if (!lexrc.next()) break; - col.b = lexrc.GetInteger(); + col.b = lexrc.getInteger(); fl_mapcolor(le, col.r, col.g, col.b); + + if (tag == "\\gui_pointer") { + setCursorColor(FL_FREE_COL16); + } } - + return true; } @@ -189,21 +383,17 @@ bool XformsColor::read(string const & filename) bool XformsColor::write(string const & filename) { ofstream os(filename.c_str()); - if (!os) + if (!os) { + lyxerr << "XformsColor::write(" << filename << ")\n" + << _("Failed to open file.") << std::endl; return false; + } - os << "### This file is part of\n" - << "### ========================================================\n" - << "### LyX, The Document Processor\n" - << "###\n" - << "### Copyright 1995 Matthias Ettrich\n" - << "### Copyright 1995-2000 The LyX Team.\n" - << "###\n" - << "### ========================================================\n" - << "\n" - << "# This file is written by LyX, if you want to make your own\n" - << "# modifications you should do them from inside LyX and save\n" - << "\n"; + os << "###" + << "### file " << filename << "\n\n" + << "### This file is written by LyX, if you want to make your own\n" + << "### modifications you should do them from inside LyX and save\n" + << '\n'; for (int i = 0; i < xformCount; ++i) { string const tag = xformTags[i].tag; @@ -212,8 +402,8 @@ bool XformsColor::write(string const & filename) fl_getmcolor(colorID, &color.r, &color.g, &color.b); - os << tag << " " - << color.r << " " << color.g << " " << color.b << "\n"; + os << tag << ' ' + << color.r << ' ' << color.g << ' ' << color.b << '\n'; } return true; @@ -227,18 +417,18 @@ bool RWInfo::WriteableDir(string const & name) error_message.erase(); if (!AbsolutePath(name)) { - error_message = N_("The absolute path is required."); + error_message = _("The absolute path is required."); return false; } FileInfo const tp(name); - if (!tp.isDir()) { - error_message = N_("Directory does not exist."); + if (!tp.isOK() || !tp.isDir()) { + error_message = _("Directory does not exist."); return false; } if (!tp.writable()) { - error_message = N_("Cannot write to this directory."); + error_message = _("Cannot write to this directory."); return false; } @@ -251,18 +441,18 @@ bool RWInfo::ReadableDir(string const & name) error_message.erase(); if (!AbsolutePath(name)) { - error_message = N_("The absolute path is required."); + error_message = _("The absolute path is required."); return false; } FileInfo const tp(name); - if (!tp.isDir()) { - error_message = N_("Directory does not exist."); + if (!tp.isOK() || !tp.isDir()) { + error_message = _("Directory does not exist."); return false; } if (!tp.readable()) { - error_message = N_("Cannot read this directory."); + error_message = _("Cannot read this directory."); return false; } @@ -280,42 +470,43 @@ bool RWInfo::WriteableFile(string const & name) error_message.erase(); if (name.empty()) { - error_message = N_("No file input."); + error_message = _("No file input."); return false; } string const dir = OnlyPath(name); if (!AbsolutePath(dir)) { - error_message = N_("The absolute path is required."); + error_message = _("The absolute path is required."); return false; } FileInfo d(name); - if (!d.isDir()) { + + if (!d.isOK() || !d.isDir()) { d.newFile(dir); } - if (!d.isDir()) { - error_message = N_("Directory does not exist."); + if (!d.isOK() || !d.isDir()) { + error_message = _("Directory does not exist."); return false; } - + if (!d.writable()) { - error_message = N_("Cannot write to this directory."); + error_message = _("Cannot write to this directory."); return false; } FileInfo f(name); - if (dir == name || f.isDir()) { - error_message = N_("A file is required, not a directory."); + if (dir == name || (f.isOK() && f.isDir())) { + error_message = _("A file is required, not a directory."); return false; } - if (f.exist() && !f.writable()) { - error_message = N_("Cannot write to this file."); + if (f.isOK() && f.exist() && !f.writable()) { + error_message = _("Cannot write to this file."); return false; } - + return true; } @@ -325,46 +516,50 @@ bool RWInfo::ReadableFile(string const & name) error_message.erase(); if (name.empty()) { - error_message = N_("No file input."); + error_message = _("No file input."); return false; } string const dir = OnlyPath(name); if (!AbsolutePath(dir)) { - error_message = N_("The absolute path is required."); + error_message = _("The absolute path is required."); return false; } FileInfo d(name); - if (!d.isDir()) { + + if (!d.isOK() && !d.isDir()) { d.newFile(dir); } - if (!d.isDir()) { - error_message = N_("Directory does not exist."); + if (!d.isOK() || !d.isDir()) { + error_message = _("Directory does not exist."); return false; } - + if (!d.readable()) { - error_message = N_("Cannot read from this directory."); + error_message = _("Cannot read from this directory."); return false; } FileInfo f(name); - if (dir == name || f.isDir()) { - error_message = N_("A file is required, not a directory."); + if (dir == name || (f.isOK() && f.isDir())) { + error_message = _("A file is required, not a directory."); return false; } if (!f.exist()) { - error_message = N_("File does not exist."); + error_message = _("File does not exist."); return false; } - + if (!f.readable()) { - error_message = N_("Cannot read from this file."); + error_message = _("Cannot read from this file."); return false; } return true; } + +} // namespace frontend +} // namespace lyx