2 * \file xforms_helpers.C
3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Angus Leeming
8 * Full author contact details are available in file CREDITS
14 #include "xforms_helpers.h"
18 #include "lyxlength.h"
19 #include "lyxgluelength.h"
21 #include "support/LAssert.h"
22 #include "support/FileInfo.h"
23 #include "support/filetools.h"
24 #include "support/lstrings.h" // frontStrip, strip
28 #include FORMS_H_LOCATION
36 bool isActive(FL_OBJECT * ob)
38 return ob && ob->active > 0;
41 std::pair<string, string> parse_shortcut(string const & str)
43 string::size_type i = str.find_first_of("&");
44 if (i == string::npos || i == str.length() - 1)
45 return make_pair(str, string());
49 string::value_type c = str[i + 1];
50 return make_pair(str.substr(0, i) + str.substr(i + 1),
55 // A wrapper for the xforms routine, but this one accepts uint args
56 unsigned long fl_getmcolor(int i,
57 unsigned int * r, unsigned int * g, unsigned int * b)
60 unsigned long ret_val = ::fl_getmcolor(i, &r2, &g2, &b2);
68 // Set an FL_OBJECT to activated or deactivated
69 void setEnabled(FL_OBJECT * ob, bool enable)
72 fl_activate_object(ob);
73 fl_set_object_lcol(ob, FL_LCOL);
75 fl_deactivate_object(ob);
76 fl_set_object_lcol(ob, FL_INACTIVE);
81 // Given an fl_choice or an fl_browser, create a vector of its entries
82 vector<string> const getVector(FL_OBJECT * ob)
86 switch (ob->objclass) {
88 for(int i = 0; i < fl_get_choice_maxitems(ob); ++i) {
89 string const text = fl_get_choice_item_text(ob, i+1);
90 vec.push_back(trim(text));
94 for(int i = 0; i < fl_get_browser_maxline(ob); ++i) {
95 string const text = fl_get_browser_line(ob, i+1);
96 vec.push_back(trim(text));
108 string const getString(FL_OBJECT * ob, int line)
110 // Negative line value does not make sense.
111 lyx::Assert(line >= 0);
113 char const * tmp = 0;
114 switch (ob->objclass) {
116 tmp = fl_get_input(ob);
121 line = fl_get_browser(ob);
123 if (line >= 1 && line <= fl_get_browser_maxline(ob))
124 tmp = fl_get_browser_line(ob, line);
129 line = fl_get_choice(ob);
131 if (line >= 1 && line <= fl_get_choice_maxitems(ob))
132 tmp = fl_get_choice_item_text(ob, line);
136 tmp = fl_get_combox_text(ob);
143 return tmp ? trim(tmp) : string();
146 string getLengthFromWidgets(FL_OBJECT * input, FL_OBJECT * choice)
149 lyx::Assert(input && input->objclass == FL_INPUT &&
150 choice && choice->objclass == FL_CHOICE);
152 string const length = trim(fl_get_input(input));
156 // don't return unit-from-choice if the input(field) contains a unit
157 if (isValidGlueLength(length))
160 string unit = trim(fl_get_choice_text(choice));
161 unit = subst(unit, "%%", "%");
163 return length + unit;
167 void updateWidgetsFromLengthString(FL_OBJECT * input, FL_OBJECT * choice,
169 string const & default_unit)
171 // use input field only for gluelengths
172 if (!isValidLength(str) && !isStrDbl(str)) {
173 fl_set_input(input, str.c_str());
174 // we assume that "default_unit" is in the choice as "we"
175 // have control over that!
176 // No need to check for its presence in the choice, therefore.
177 fl_set_choice_text(choice, default_unit.c_str());
179 updateWidgetsFromLength(input, choice,
180 LyXLength(str), default_unit);
185 void updateWidgetsFromLength(FL_OBJECT * input, FL_OBJECT * choice,
186 LyXLength const & len,
187 string const & default_unit)
190 lyx::Assert(input && input->objclass == FL_INPUT &&
191 choice && choice->objclass == FL_CHOICE);
194 fl_set_input(input, "");
195 fl_set_choice_text(choice, default_unit.c_str());
197 ostringstream buffer;
198 buffer << len.value();
199 fl_set_input(input, buffer.str().c_str());
201 // Set the choice to the desired unit, if present in the choice.
202 // Else set the choice to the default unit.
203 string const unit = subst(stringFromUnit(len.unit()),"%","%%");
205 vector<string> const vec = getVector(choice);
206 vector<string>::const_iterator it =
207 std::find(vec.begin(), vec.end(), unit);
208 if (it != vec.end()) {
209 fl_set_choice_text(choice, unit.c_str());
211 fl_set_choice_text(choice, default_unit.c_str());
217 // Take a string and add breaks so that it fits into a desired label width, w
218 string formatted(string const & sin, int w, int size, int style)
221 if (sin.empty()) return sout;
223 string::size_type curpos = 0;
226 string::size_type const nxtpos1 = sin.find(' ', curpos);
227 string::size_type const nxtpos2 = sin.find('\n', curpos);
228 string::size_type const nxtpos = std::min(nxtpos1, nxtpos2);
230 string const word = nxtpos == string::npos ?
231 sin.substr(curpos) : sin.substr(curpos, nxtpos-curpos);
233 bool const newline = (nxtpos2 != string::npos &&
236 string const line_plus_word =
237 line.empty() ? word : line + ' ' + word;
240 fl_get_string_width(style, size,
241 line_plus_word.c_str(),
242 int(line_plus_word.length()));
253 } else if (newline) {
254 sout += line_plus_word + '\n';
263 if (nxtpos == string::npos) {
276 void setCursorColor(int color)
278 fl_set_cursor_color(FL_DEFAULT_CURSOR, color, FL_WHITE);
279 fl_set_cursor_color(XC_xterm, color, FL_WHITE);
280 fl_set_cursor_color(XC_watch, color, FL_WHITE);
281 fl_set_cursor_color(XC_sb_right_arrow, color, FL_WHITE);
287 // sorted by hand to prevent LyXLex from complaining on read().
288 keyword_item xformTags[] = {
289 { "\\gui_background", FL_COL1 },
290 { "\\gui_buttonbottom", FL_BOTTOM_BCOL },
291 { "\\gui_buttonleft", FL_LEFT_BCOL },
292 { "\\gui_buttonright", FL_RIGHT_BCOL },
293 { "\\gui_buttontop", FL_TOP_BCOL },
294 { "\\gui_inactive", FL_INACTIVE },
295 { "\\gui_pointer", FL_FREE_COL16 },
296 { "\\gui_push_button", FL_YELLOW },
297 { "\\gui_selected", FL_MCOL },
298 { "\\gui_text", FL_BLACK }
302 const int xformCount = sizeof(xformTags) / sizeof(keyword_item);
307 bool XformsColor::read(string const & filename)
309 LyXLex lexrc(xformTags, xformCount);
310 if (!lexrc.setFile(filename))
313 while (lexrc.isOK()) {
314 int const le = lexrc.lex();
317 case LyXLex::LEX_UNDEF:
318 lexrc.printError("Unknown tag `$$Token'");
320 case LyXLex::LEX_FEOF:
325 string const tag = lexrc.getString();
329 if (!lexrc.next()) break;
330 col.r = lexrc.getInteger();
332 if (!lexrc.next()) break;
333 col.g = lexrc.getInteger();
335 if (!lexrc.next()) break;
336 col.b = lexrc.getInteger();
338 fl_mapcolor(le, col.r, col.g, col.b);
340 if (tag == "\\gui_pointer") {
341 setCursorColor(FL_FREE_COL16);
349 bool XformsColor::write(string const & filename)
351 ofstream os(filename.c_str());
356 << "### file " << filename << "\n\n"
357 << "### This file is written by LyX, if you want to make your own\n"
358 << "### modifications you should do them from inside LyX and save\n"
361 for (int i = 0; i < xformCount; ++i) {
362 string const tag = xformTags[i].tag;
363 int const colorID = xformTags[i].code;
366 fl_getmcolor(colorID, &color.r, &color.g, &color.b);
369 << color.r << ' ' << color.g << ' ' << color.b << '\n';
376 string RWInfo::error_message;
378 bool RWInfo::WriteableDir(string const & name)
380 error_message.erase();
382 if (!AbsolutePath(name)) {
383 error_message = _("The absolute path is required.");
387 FileInfo const tp(name);
388 if (!tp.isOK() || !tp.isDir()) {
389 error_message = _("Directory does not exist.");
393 if (!tp.writable()) {
394 error_message = _("Cannot write to this directory.");
402 bool RWInfo::ReadableDir(string const & name)
404 error_message.erase();
406 if (!AbsolutePath(name)) {
407 error_message = _("The absolute path is required.");
411 FileInfo const tp(name);
412 if (!tp.isOK() || !tp.isDir()) {
413 error_message = _("Directory does not exist.");
417 if (!tp.readable()) {
418 error_message = _("Cannot read this directory.");
426 bool RWInfo::WriteableFile(string const & name)
428 // A writeable file is either:
429 // * An existing file to which we have write access, or
430 // * A file that doesn't yet exist but that would exist in a writeable
433 error_message.erase();
436 error_message = _("No file input.");
440 string const dir = OnlyPath(name);
441 if (!AbsolutePath(dir)) {
442 error_message = _("The absolute path is required.");
448 if (!d.isOK() || !d.isDir()) {
452 if (!d.isOK() || !d.isDir()) {
453 error_message = _("Directory does not exist.");
458 error_message = _("Cannot write to this directory.");
463 if (dir == name || (f.isOK() && f.isDir())) {
464 error_message = _("A file is required, not a directory.");
468 if (f.isOK() && f.exist() && !f.writable()) {
469 error_message = _("Cannot write to this file.");
477 bool RWInfo::ReadableFile(string const & name)
479 error_message.erase();
482 error_message = _("No file input.");
486 string const dir = OnlyPath(name);
487 if (!AbsolutePath(dir)) {
488 error_message = _("The absolute path is required.");
494 if (!d.isOK() && !d.isDir()) {
498 if (!d.isOK() || !d.isDir()) {
499 error_message = _("Directory does not exist.");
504 error_message = _("Cannot read from this directory.");
509 if (dir == name || (f.isOK() && f.isDir())) {
510 error_message = _("A file is required, not a directory.");
515 error_message = _("File does not exist.");
520 error_message = _("Cannot read from this file.");